def main(path="/skynet3_rech1/huziy/gemclim_settings.nml"): params = _parse_parameters(path) print(params) ni, nj = 140, 140 # params[Grd_ni_name], params[Grd_nj_name] dx, dy = params[Grd_dx_name], params[Grd_dy_name] iRef, jRef = params[Grd_iref_name] - 1, params[Grd_jref_name] - 1 lonRef, latRef = params[Grd_lonr_name], params[Grd_latr_name] lon1, lat1 = params[Grd_xlon1_name], params[Grd_xlat1_name] lon2, lat2 = params[Grd_xlon2_name], params[Grd_xlat2_name] lons_rot = np.arange(lonRef + (0 - iRef) * dx, lonRef + (ni - iRef) * dx, dx) lats_rot = np.arange(latRef + (0 - jRef) * dy, latRef + (nj - jRef) * dy, dy) lats_rot, lons_rot = np.meshgrid(lats_rot, lons_rot) print(lats_rot.shape) # lons_rot[lons_rot > 180] -= 360 rll = RotatedLatLon(lon1=lon1, lat1=lat1, lon2=lon2, lat2=lat2) truepole_lonr, truepole_latr = rll.get_true_pole_coords_in_rotated_system() rotpole_lon, rotpole_lat = rll.get_north_pole_coords() llcrnrlon, llcrnrlat = rll.toGeographicLonLat(lons_rot[0, 0], lats_rot[0, 0]) urcrnrlon, urcrnrlat = rll.toGeographicLonLat(lons_rot[-1, -1], lats_rot[-1, -1]) b = Basemap(projection="rotpole", lon_0=truepole_lonr - 180, o_lat_p=rotpole_lat, o_lon_p=rotpole_lon, llcrnrlon=llcrnrlon, llcrnrlat=llcrnrlat, urcrnrlon=urcrnrlon, urcrnrlat=urcrnrlat) print(lons_rot[0, 0], lats_rot[0, 0], lons_rot[-1, -1], lats_rot[-1, -1]) b.contourf(lons_rot, lats_rot, lons_rot) b.colorbar() b.drawcoastlines() # b.drawmeridians(np.arange(160, 200, 10)) plt.show()
def main(path="/skynet3_rech1/huziy/gemclim_settings.nml"): params = _parse_parameters(path) print(params) ni, nj = 140, 140 # params[Grd_ni_name], params[Grd_nj_name] dx, dy = params[Grd_dx_name], params[Grd_dy_name] iRef, jRef = params[Grd_iref_name] - 1, params[Grd_jref_name] - 1 lonRef, latRef = params[Grd_lonr_name], params[Grd_latr_name] lon1, lat1 = params[Grd_xlon1_name], params[Grd_xlat1_name] lon2, lat2 = params[Grd_xlon2_name], params[Grd_xlat2_name] lons_rot = np.arange(lonRef + (0 - iRef) * dx, lonRef + (ni - iRef) * dx, dx) lats_rot = np.arange(latRef + (0 - jRef) * dy, latRef + (nj - jRef) * dy, dy) lats_rot, lons_rot = np.meshgrid(lats_rot, lons_rot) print(lats_rot.shape) # lons_rot[lons_rot > 180] -= 360 rll = RotatedLatLon(lon1=lon1, lat1=lat1, lon2=lon2, lat2=lat2) truepole_lonr, truepole_latr = rll.get_true_pole_coords_in_rotated_system() rotpole_lon, rotpole_lat = rll.get_north_pole_coords() llcrnrlon, llcrnrlat = rll.toGeographicLonLat(lons_rot[0, 0], lats_rot[0, 0]) urcrnrlon, urcrnrlat = rll.toGeographicLonLat(lons_rot[-1, -1], lats_rot[-1, -1]) b = Basemap( projection="rotpole", lon_0=truepole_lonr - 180, o_lat_p=rotpole_lat, o_lon_p=rotpole_lon, llcrnrlon=llcrnrlon, llcrnrlat=llcrnrlat, urcrnrlon=urcrnrlon, urcrnrlat=urcrnrlat, ) print(lons_rot[0, 0], lats_rot[0, 0], lons_rot[-1, -1], lats_rot[-1, -1]) b.contourf(lons_rot, lats_rot, lons_rot) b.colorbar() b.drawcoastlines() # b.drawmeridians(np.arange(160, 200, 10)) plt.show()
def main(inout_paths): tiff_path, rpn_path = inout_paths print("tif path = {0}".format(tiff_path)) print("rpn path = {0}".format(rpn_path)) outGrid = RotatedLatLon(lon1=-90.0, lat1=50.0, lon2=0.0, lat2=0.0) Grd_dx = 0.5 Grd_dy = 0.5 Grd_ni = 170 Grd_nj = 158 Grd_iref = 11 Grd_jref = 11 Grd_latr = -33.5 Grd_lonr = 140.5 lons1d = np.array( [Grd_lonr + (i - Grd_iref + 1) * Grd_dx for i in range(Grd_ni)]) lats1d = np.array( [Grd_latr + (j - Grd_jref + 1) * Grd_dy for j in range(Grd_nj)]) lats2d, lons2d = np.meshgrid(lats1d, lons1d) lonlats = np.array( list( map(lambda x, y: outGrid.toGeographicLonLat(x, y), lons2d.flatten(), lats2d.flatten()))) print(lonlats.shape) rObj = RPN(rpn_path, mode="w") data = convert(tiff_path, lonlats) print("interpolated data") data.shape = lons2d.shape fieldName = os.path.basename(tiff_path).split("_")[0].lower() #write coordinates ig = outGrid.write_coords_to_rpn(rObj, lons1d, lats1d) rObj.write_2D_field(name=fieldName, data=data, grid_type="Z", ig=ig, label=fieldName) rObj.close() return 0 pass
def main(inout_paths): tiff_path, rpn_path = inout_paths print("tif path = {0}".format(tiff_path)) print("rpn path = {0}".format(rpn_path)) outGrid = RotatedLatLon(lon1=-90.0, lat1=50.0, lon2=0.0, lat2=0.0) Grd_dx = 0.5 Grd_dy = 0.5 Grd_ni = 170 Grd_nj = 158 Grd_iref = 11 Grd_jref = 11 Grd_latr = -33.5 Grd_lonr = 140.5 lons1d = np.array([Grd_lonr + (i - Grd_iref + 1) * Grd_dx for i in range(Grd_ni)]) lats1d = np.array([Grd_latr + (j - Grd_jref + 1) * Grd_dy for j in range(Grd_nj)]) lats2d, lons2d = np.meshgrid(lats1d, lons1d) lonlats = np.array( list(map( lambda x, y: outGrid.toGeographicLonLat(x, y), lons2d.flatten(), lats2d.flatten() )) ) print(lonlats.shape) rObj = RPN(rpn_path, mode = "w") data = convert(tiff_path, lonlats) print("interpolated data") data.shape = lons2d.shape fieldName = os.path.basename(tiff_path).split("_")[0].lower() #write coordinates ig = outGrid.write_coords_to_rpn(rObj, lons1d, lats1d) rObj.write_2D_field(name = fieldName, data=data, grid_type="Z", ig = ig, label = fieldName) rObj.close() return 0 pass
def plot_domain_for_different_margins(path, margins=None): if not margins: margins = [20, 40, 60] rpnObj = RPN(path) lons2d, lats2d = rpnObj.get_longitudes_and_latitudes() # projection parameters lon_1 = -68 lat_1 = 52 lon_2 = 16.65 lat_2 = 0.0 rot_lat_lon = RotatedLatLon(lon1=lon_1, lat1=lat_1, lon2=lon_2, lat2=lat_2) xll, yll = rot_lat_lon.toProjectionXY(lons2d[0, 0], lats2d[0, 0]) xur, yur = rot_lat_lon.toProjectionXY(lons2d[-1, -1], lats2d[-1, -1]) if xll < 0: xll += 360.0 if xur < 0: xur += 360.0 nx, ny = lons2d.shape dx = (xur - xll) / float(nx - 1) dy = (yur - yll) / float(ny - 1) print(dx, dy) print(xur, yur, xll, yll) x1 = xll - dx / 2.0 y1 = yll - dy / 2.0 x2 = xur + dx / 2.0 y2 = yur + dy / 2.0 x1lon, y1lat = rot_lat_lon.toGeographicLonLat(x1, y1) x2lon, y2lat = rot_lat_lon.toGeographicLonLat(x2, y2) llcrnrlon, llcrnrlat = rot_lat_lon.toGeographicLonLat(x1 - dx, y1 - dx) urcrnrlon, urcrnrlat = rot_lat_lon.toGeographicLonLat(x2 + dx, y2 + dx) basemap = Basemap(projection="omerc", lon_1=lon_1, lat_1=lat_1, lon_2=lon_2, lat_2=lat_2, llcrnrlon=llcrnrlon, llcrnrlat=llcrnrlat, urcrnrlon=urcrnrlon, urcrnrlat=urcrnrlat, no_rot=True, resolution="l") basemap.drawcoastlines() basemap.drawrivers() x1, y1 = basemap(x1lon, y1lat) x2, y2 = basemap(x2lon, y2lat) # add rectangle for the grid 220x220 # r1 = Rectangle((x1, y1), x2-x1, y2-y1, facecolor="none", edgecolor="r", linewidth=5 ) ax = plt.gca() assert isinstance(ax, Axes) # xr1_label, yr1_label = rot_lat_lon.toGeographicLonLat(xur - 2 * dx, yll + 2 * dy) # xr1_label, yr1_label = basemap( xr1_label, yr1_label ) # ax.annotate("{0}x{1}".format(nx, ny), xy = (xr1_label, yr1_label), va = "bottom", ha = "right", color = "r") # assert isinstance(ax, Axes) # ax.add_patch(r1) margins_all = [0] + margins for margin in margins_all: # mfree = margin - 20 xlli = xll + margin * dx ylli = yll + margin * dy xuri = xur - margin * dx yuri = yur - margin * dy x1lon, y1lat = rot_lat_lon.toGeographicLonLat(xlli, ylli) x2lon, y2lat = rot_lat_lon.toGeographicLonLat(xuri, yuri) x1, y1 = basemap(x1lon, y1lat) x2, y2 = basemap(x2lon, y2lat) ri = Rectangle((x1, y1), x2 - x1, y2 - y1, facecolor="none", edgecolor="r", linewidth=5) ax.add_patch(ri) xri_label, yri_label = rot_lat_lon.toGeographicLonLat( xlli + 2 * dx, yuri - 2 * dy) xri_label, yri_label = basemap(xri_label, yri_label) ax.annotate("{0}x{1}\nmarg. = {2}".format(nx - margin * 2, ny - margin * 2, margin + 20), xy=(xri_label, yri_label), va="top", ha="left", color="k", backgroundcolor="w") plt.show()
def plot_domain_using_coords_from_file(path=""): fig = plt.figure() assert isinstance(fig, Figure) rpnObj = RPN(path) lons2d, lats2d = rpnObj.get_longitudes_and_latitudes() basemap = Basemap(projection="omerc", lon_1=-68, lat_1=52, lon_2=16.65, lat_2=0.0, llcrnrlon=lons2d[0, 0], llcrnrlat=lats2d[0, 0], urcrnrlon=lons2d[-1, -1], urcrnrlat=lats2d[-1, -1], no_rot=True) # basemap.drawcoastlines() rot_lat_lon_proj = RotatedLatLon(lon1=-68, lat1=52, lon2=16.65, lat2=0.0) g_params = GridParams(lonr=180, latr=0, iref=45, jref=41, dx=0.5, dy=0.5, nx=86, ny=86) lons2d_1, lats2d_1 = get_lons_lats_using_grid_params( g_params, rot_lat_lon_proj) basemap = Basemap(projection="omerc", lon_1=-68, lat_1=52, lon_2=16.65, lat_2=0.0, llcrnrlon=lons2d_1[18, 18], llcrnrlat=lats2d_1[18, 18], urcrnrlon=lons2d_1[-1, -1], urcrnrlat=lats2d_1[-1, -1], no_rot=True, resolution="i") basemap.drawcoastlines(linewidth=0.4) basemap.drawrivers() # basemap.drawmeridians(np.arange(-180, 0, 20)) x, y = basemap(lons2d, lats2d) basemap.scatter(x, y, c="r", linewidths=0, s=1.0) print(x.shape) xll_big, yll_big = g_params.get_ll_point(marginx=20, marginy=20) xll_big -= g_params.dx / 2.0 yll_big -= g_params.dy / 2.0 xll_big, yll_big = rot_lat_lon_proj.toGeographicLonLat(xll_big, yll_big) xll_big, yll_big = basemap(xll_big, yll_big) xur_big, yur_big = g_params.get_ur_point(marginx=20, marginy=20) xur_big += g_params.dx / 2.0 yur_big += g_params.dy / 2.0 xur_big, yur_big = rot_lat_lon_proj.toGeographicLonLat(xur_big, yur_big) xur_big, yur_big = basemap(xur_big, yur_big) margin = 20 # plot 0.25 degree grid g_params = GridParams(lonr=180, latr=0, iref=71, jref=63, dx=0.25, dy=0.25, nx=133, ny=133) lons2d_2, lats2d_2 = get_lons_lats_using_grid_params( g_params, rot_lat_lon_proj) x2, y2 = basemap(lons2d_2[margin:-margin, margin:-margin], lats2d_2[margin:-margin, margin:-margin]) basemap.scatter(x2, y2, c="g", linewidth=0, marker="s", s=7.5) # plot 0.5 degree grid using the output file # debug rObj1 = RPN( "/home/huziy/skynet3_exec1/from_guillimin/quebec_86x86_0.5deg_without_lakes/pm1985010100_00000000p" ) lons2d_1, lats2d_1 = rObj1.get_longitudes_and_latitudes() # x1, y1 = basemap(lons2d_1[margin:-margin,margin:-margin], lats2d_1[margin:-margin,margin:-margin]) x1, y1 = basemap(lons2d_1, lats2d_1) print(x1.shape, lons2d_1[0, 0], lats2d_1[0, 0]) basemap.scatter(x1, y1, c="b", linewidths=0, s=10) dx1 = (x1[1, 0] - x1[0, 0]) / 2.0 dy1 = (y1[0, 1] - y1[0, 0]) / 2.0 rbig = Rectangle((xll_big, yll_big), xur_big - xll_big, yur_big - yll_big, linewidth=2, edgecolor="b", facecolor="none") ax = plt.gca() assert isinstance(ax, Axes) # ax.add_patch(rsmall) ax.add_patch(rbig) # draw north arrow plot_north_cross(-45, 45, basemap, ax=ax) # zoom to a region axins = zoomed_inset_axes(ax, 4, loc=1) # zoom = 6 basemap.drawcoastlines(ax=axins) basemap.drawrivers(ax=axins) basemap.scatter(x, y, c="r", linewidths=0, s=5, ax=axins) basemap.scatter(x2, y2, c="g", marker="s", linewidth=0, s=15, ax=axins) basemap.scatter(x1, y1, c="b", linewidths=0, s=25, ax=axins) # subregion to zoom in nx, ny = lons2d.shape part = 3 xins_ll = lons2d[nx / part, ny / part] yins_ll = lats2d[nx / part, ny / part] xins_ur = lons2d[nx / part + 40, ny / part + 40] yins_ur = lats2d[nx / part + 40, ny / part + 40] xins_ll, yins_ll = basemap(xins_ll, yins_ll) xins_ur, yins_ur = basemap(xins_ur, yins_ur) axins.set_xlim(xins_ll, xins_ur) axins.set_ylim(yins_ll, yins_ur) # draw a bbox of the region of the inset axes in the parent axes and # connecting lines between the bbox and the inset axes area mark_inset(ax, axins, loc1=2, loc2=4, fc="none", linewidth=2) fig.tight_layout(pad=0.8) fig.savefig("high_low_res_domains.png") pass
def plot_domain_for_different_margins(path, margins=None): if not margins: margins = [20, 40, 60] rpnObj = RPN(path) lons2d, lats2d = rpnObj.get_longitudes_and_latitudes() # projection parameters lon_1 = -68 lat_1 = 52 lon_2 = 16.65 lat_2 = 0.0 rot_lat_lon = RotatedLatLon(lon1=lon_1, lat1=lat_1, lon2=lon_2, lat2=lat_2) xll, yll = rot_lat_lon.toProjectionXY(lons2d[0, 0], lats2d[0, 0]) xur, yur = rot_lat_lon.toProjectionXY(lons2d[-1, -1], lats2d[-1, -1]) if xll < 0: xll += 360.0 if xur < 0: xur += 360.0 nx, ny = lons2d.shape dx = (xur - xll) / float(nx - 1) dy = (yur - yll) / float(ny - 1) print(dx, dy) print(xur, yur, xll, yll) x1 = xll - dx / 2.0 y1 = yll - dy / 2.0 x2 = xur + dx / 2.0 y2 = yur + dy / 2.0 x1lon, y1lat = rot_lat_lon.toGeographicLonLat(x1, y1) x2lon, y2lat = rot_lat_lon.toGeographicLonLat(x2, y2) llcrnrlon, llcrnrlat = rot_lat_lon.toGeographicLonLat(x1 - dx, y1 - dx) urcrnrlon, urcrnrlat = rot_lat_lon.toGeographicLonLat(x2 + dx, y2 + dx) basemap = Basemap(projection="omerc", lon_1=lon_1, lat_1=lat_1, lon_2=lon_2, lat_2=lat_2, llcrnrlon=llcrnrlon, llcrnrlat=llcrnrlat, urcrnrlon=urcrnrlon, urcrnrlat=urcrnrlat, no_rot=True, resolution="l") basemap.drawcoastlines() basemap.drawrivers() x1, y1 = basemap(x1lon, y1lat) x2, y2 = basemap(x2lon, y2lat) # add rectangle for the grid 220x220 # r1 = Rectangle((x1, y1), x2-x1, y2-y1, facecolor="none", edgecolor="r", linewidth=5 ) ax = plt.gca() assert isinstance(ax, Axes) # xr1_label, yr1_label = rot_lat_lon.toGeographicLonLat(xur - 2 * dx, yll + 2 * dy) # xr1_label, yr1_label = basemap( xr1_label, yr1_label ) # ax.annotate("{0}x{1}".format(nx, ny), xy = (xr1_label, yr1_label), va = "bottom", ha = "right", color = "r") # assert isinstance(ax, Axes) # ax.add_patch(r1) margins_all = [0] + margins for margin in margins_all: # mfree = margin - 20 xlli = xll + margin * dx ylli = yll + margin * dy xuri = xur - margin * dx yuri = yur - margin * dy x1lon, y1lat = rot_lat_lon.toGeographicLonLat(xlli, ylli) x2lon, y2lat = rot_lat_lon.toGeographicLonLat(xuri, yuri) x1, y1 = basemap(x1lon, y1lat) x2, y2 = basemap(x2lon, y2lat) ri = Rectangle((x1, y1), x2 - x1, y2 - y1, facecolor="none", edgecolor="r", linewidth=5) ax.add_patch(ri) xri_label, yri_label = rot_lat_lon.toGeographicLonLat(xlli + 2 * dx, yuri - 2 * dy) xri_label, yri_label = basemap(xri_label, yri_label) ax.annotate("{0}x{1}\nmarg. = {2}".format(nx - margin * 2, ny - margin * 2, margin + 20), xy=(xri_label, yri_label), va="top", ha="left", color="k", backgroundcolor="w") plt.show()
def plot_domain_using_coords_from_file(path=""): fig = plt.figure() assert isinstance(fig, Figure) rpnObj = RPN(path) lons2d, lats2d = rpnObj.get_longitudes_and_latitudes() basemap = Basemap(projection="omerc", lon_1=-68, lat_1=52, lon_2=16.65, lat_2=0.0, llcrnrlon=lons2d[0, 0], llcrnrlat=lats2d[0, 0], urcrnrlon=lons2d[-1, -1], urcrnrlat=lats2d[-1, -1], no_rot=True) # basemap.drawcoastlines() rot_lat_lon_proj = RotatedLatLon(lon1=-68, lat1=52, lon2=16.65, lat2=0.0) g_params = GridParams(lonr=180, latr=0, iref=45, jref=41, dx=0.5, dy=0.5, nx=86, ny=86) lons2d_1, lats2d_1 = get_lons_lats_using_grid_params(g_params, rot_lat_lon_proj) basemap = Basemap(projection="omerc", lon_1=-68, lat_1=52, lon_2=16.65, lat_2=0.0, llcrnrlon=lons2d_1[18, 18], llcrnrlat=lats2d_1[18, 18], urcrnrlon=lons2d_1[-1, -1], urcrnrlat=lats2d_1[-1, -1], no_rot=True, resolution="i") basemap.drawcoastlines(linewidth=0.4) basemap.drawrivers() # basemap.drawmeridians(np.arange(-180, 0, 20)) x, y = basemap(lons2d, lats2d) basemap.scatter(x, y, c="r", linewidths=0, s=1.0) print(x.shape) xll_big, yll_big = g_params.get_ll_point(marginx=20, marginy=20) xll_big -= g_params.dx / 2.0 yll_big -= g_params.dy / 2.0 xll_big, yll_big = rot_lat_lon_proj.toGeographicLonLat(xll_big, yll_big) xll_big, yll_big = basemap(xll_big, yll_big) xur_big, yur_big = g_params.get_ur_point(marginx=20, marginy=20) xur_big += g_params.dx / 2.0 yur_big += g_params.dy / 2.0 xur_big, yur_big = rot_lat_lon_proj.toGeographicLonLat(xur_big, yur_big) xur_big, yur_big = basemap(xur_big, yur_big) margin = 20 # plot 0.25 degree grid g_params = GridParams(lonr=180, latr=0, iref=71, jref=63, dx=0.25, dy=0.25, nx=133, ny=133) lons2d_2, lats2d_2 = get_lons_lats_using_grid_params(g_params, rot_lat_lon_proj) x2, y2 = basemap(lons2d_2[margin:-margin, margin:-margin], lats2d_2[margin:-margin, margin:-margin]) basemap.scatter(x2, y2, c="g", linewidth=0, marker="s", s=7.5) # plot 0.5 degree grid using the output file # debug rObj1 = RPN("/home/huziy/skynet3_exec1/from_guillimin/quebec_86x86_0.5deg_without_lakes/pm1985010100_00000000p") lons2d_1, lats2d_1 = rObj1.get_longitudes_and_latitudes() # x1, y1 = basemap(lons2d_1[margin:-margin,margin:-margin], lats2d_1[margin:-margin,margin:-margin]) x1, y1 = basemap(lons2d_1, lats2d_1) print(x1.shape, lons2d_1[0, 0], lats2d_1[0, 0]) basemap.scatter(x1, y1, c="b", linewidths=0, s=10) dx1 = (x1[1, 0] - x1[0, 0]) / 2.0 dy1 = (y1[0, 1] - y1[0, 0]) / 2.0 rbig = Rectangle((xll_big, yll_big), xur_big - xll_big, yur_big - yll_big, linewidth=2, edgecolor="b", facecolor="none" ) ax = plt.gca() assert isinstance(ax, Axes) # ax.add_patch(rsmall) ax.add_patch(rbig) # draw north arrow plot_north_cross(-45, 45, basemap, ax=ax) # zoom to a region axins = zoomed_inset_axes(ax, 4, loc=1) # zoom = 6 basemap.drawcoastlines(ax=axins) basemap.drawrivers(ax=axins) basemap.scatter(x, y, c="r", linewidths=0, s=5, ax=axins) basemap.scatter(x2, y2, c="g", marker="s", linewidth=0, s=15, ax=axins) basemap.scatter(x1, y1, c="b", linewidths=0, s=25, ax=axins) # subregion to zoom in nx, ny = lons2d.shape part = 3 xins_ll = lons2d[nx / part, ny / part] yins_ll = lats2d[nx / part, ny / part] xins_ur = lons2d[nx / part + 40, ny / part + 40] yins_ur = lats2d[nx / part + 40, ny / part + 40] xins_ll, yins_ll = basemap(xins_ll, yins_ll) xins_ur, yins_ur = basemap(xins_ur, yins_ur) axins.set_xlim(xins_ll, xins_ur) axins.set_ylim(yins_ll, yins_ur) # draw a bbox of the region of the inset axes in the parent axes and # connecting lines between the bbox and the inset axes area mark_inset(ax, axins, loc1=2, loc2=4, fc="none", linewidth=2) fig.tight_layout(pad=0.8) fig.savefig("high_low_res_domains.png") pass
class GridConfig(object): projection = "rotpole" def __init__(self, **kwargs): self.dx = self.dy = kwargs.get("dx", -1) self.iref, self.jref = kwargs.get("iref", -1), kwargs.get("jref", -1) self.xref, self.yref = kwargs.get("xref", -1), kwargs.get("yref", -1) self.ni, self.nj = kwargs.get("ni", -1), kwargs.get("nj", -1) # interpolated driving data (width of the outer band in number of gridpoints) self.halo = 10 # size of the blending zone in grid points self.blendig = 10 self.rll = None if "rll" not in kwargs: self.lon1, self.lat1 = kwargs.get("lon1", None), kwargs.get("lat1", None) self.lon2, self.lat2 = kwargs.get("lon2", None), kwargs.get("lat2", None) if None not in (self.lon1, self.lon2, self.lat1, self.lat2): self.rll = RotatedLatLon(lon1=self.lon1, lon2=self.lon2, lat1=self.lat1, lat2=self.lat2) else: self.rll = kwargs.get("rll") @classmethod def get_default_for_resolution(cls, res=0.5): """ :param res: :rtype GridConfig """ obj = GridConfig() obj.dx = obj.dy = res if res == 0.5: obj.iref = 46 # starts from 1 not 0!! obj.jref = 42 # starts from 1 not 0!! obj.ni = 86 obj.nj = 86 elif res == 0.1: obj.iref = 142 # no need to do -1, doing it later in the formulas obj.jref = 122 obj.xref = 180 # rotated longitude obj.yref = 0 # rotated latitude # projection parameters obj.lon1 = -68.0 obj.lat1 = 52.0 obj.lon2 = 16.65 obj.lat2 = 0.0 obj.ni = 260 obj.nj = 260 return obj def export_to_shape(self, shp_folder="", shp_filename="", free_zone_only=True, export_mask=None, shape_fields=None): """ export the grid to the shape file :param export_mask: Mask to specify exactly which gridcells should be exported :param free_zone_only: :param shp_folder: :param shp_filename: """ import shapefile as shp w = shp.Writer(shp.POLYGON) w.field("i", fieldType="I") w.field("j", fieldType="I") field_names_in_order = ["i", "j"] if shape_fields is not None: for field_name, field in shape_fields.items(): w.field(field_name, *field.type_of_shp_field) field_names_in_order.append(field_name) if isinstance(shp_folder, str): folder = Path(shp_folder) else: folder = shp_folder # create the directory if does not exist if not folder.is_dir(): folder.mkdir() lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 if export_mask is None: export_mask = np.ones((self.ni, self.nj), dtype=bool) for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] if not export_mask[i, j]: continue p00 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y - self.dy / 2.0) p01 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y + self.dy / 2.0) p11 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y + self.dy / 2.0) p10 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y - self.dy / 2.0) w.poly(parts=[ [p00, p01, p11, p10] ]) if shape_fields is None: w.record(i + 1, j + 1) else: record_fields = {} record_fields["i"] = i + 1 record_fields["j"] = j + 1 for field_name, field in shape_fields.items(): record_fields[field_name] = field[i, j] w.record(*[record_fields[key] for key in field_names_in_order]) # w.poly(parts=[[[-20, -20], [-20, 20], [20, 20], [20, -20]],]) # w.record(1, 1) w.save(str(folder.joinpath(shp_filename))) def export_to_shape_fiona(self, shp_folder="", shp_filename="", free_zone_only=True, export_mask=None, shape_fields=None): """ export the grid to the shape file using fiona since pyshp was not compatible with arcgis :param export_mask: Mask to specify exactly which gridcells should be exported :param free_zone_only: :param shp_folder: :param shp_filename: """ from fiona.crs import from_epsg, from_string import fiona proj = from_epsg(4326) # proj = from_epsg(4269) # proj = from_string("+units=m +lon_0=-97.0 +o_lon_p=180.0 +R=6370997.0 +o_proj=longlat +proj=ob_tran +o_lat_p=42.5") print(proj) print(dir(proj)) # proj = from_epsg(900913) if isinstance(shp_folder, str): folder = Path(shp_folder) else: folder = shp_folder # create the directory if does not exist if not folder.is_dir(): folder.mkdir() schema = { "geometry": "Polygon", "properties": OrderedDict( [("i", "int"), ("j", "int")] ) } if shape_fields is not None: # additional fields for field_name, field in shape_fields.items(): schema["properties"][field_name] = field.type_of_shp_field with fiona.open(str(folder.joinpath(shp_filename)), mode="w", driver="ESRI Shapefile", crs=proj, schema=schema) as output: lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 if export_mask is None: export_mask = np.ones((self.ni, self.nj), dtype=bool) polygons = [] lake_fractions = [] for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] if not export_mask[i, j]: continue p00 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y - self.dy / 2.0) p01 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y + self.dy / 2.0) p11 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y + self.dy / 2.0) p10 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y - self.dy / 2.0) # p00 = (x - self.dx / 2.0, y - self.dy / 2.0) # p01 = (x - self.dx / 2.0, y + self.dy / 2.0) # p11 = (x + self.dx / 2.0, y + self.dy / 2.0) # p10 = (x + self.dx / 2.0, y - self.dy / 2.0) poly = Polygon(shell=[p00, p01, p11, p10, p00]) props = OrderedDict([("i", i + 1), ("j", j + 1)]) polygons.append(PolygonPatch(poly)) if shape_fields is not None: lake_fractions.append(shape_fields["lkfr"][i, j]) for field_name, field in shape_fields.items(): converter = float if field.type_of_shp_field in ["float"] else int props[field_name] = converter(field[i, j]) output.write({"geometry": mapping(poly), "properties": props}) # plot the gridcells with basemap # pcol = PatchCollection(polygons, cmap="bone_r") # pcol.set_array(np.array(lake_fractions)) # import matplotlib.pyplot as plt # bmp = self.get_basemap_for_free_zone(resolution="l") # fig = plt.figure() # ax = fig.add_subplot(111) # bmp.ax = ax # ax.add_collection(pcol) # bmp.drawcoastlines(ax=ax) # plt.show() def export_to_shape_ogr(self, shp_folder="", shp_filename="", free_zone_only=True): """ export the grid to the shape file :param free_zone_only: :param shp_folder: :param shp_filename: """ from osgeo import ogr, osr folder = Path(shp_folder) # create the directory if does not exist if not folder.is_dir(): folder.mkdir() # set up the shapefile driver driver = ogr.GetDriverByName("ESRI Shapefile") if not shp_filename.lower().endswith(".shp"): shp_filename += ".shp" # create the data source data_source = driver.CreateDataSource(str(folder.joinpath(shp_filename))) srs = osr.SpatialReference() srs.ImportFromWkt(osr.SRS_WKT_WGS84) print(srs) print(srs.ExportToPrettyWkt()) # create the layer layer = data_source.CreateLayer("grid", srs, ogr.wkbPolygon) layer.CreateField(ogr.FieldDefn("i", ogr.OFTInteger)) layer.CreateField(ogr.FieldDefn("j", ogr.OFTInteger)) lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] # create the feature feature = ogr.Feature(layer.GetLayerDefn()) p00 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y - self.dy / 2.0) p01 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y + self.dy / 2.0) p11 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y + self.dy / 2.0) p10 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y - self.dy / 2.0) ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(*p00) ring.AddPoint(*p01) ring.AddPoint(*p11) ring.AddPoint(*p10) poly = ogr.Geometry(ogr.wkbPolygon) poly.AddGeometry(ring) feature.SetField("i", i + 1) feature.SetField("j", j + 1) feature.SetGeometry(poly) layer.CreateFeature(feature) feature.Destroy() # w.poly(parts=[[[-20, -20], [-20, 20], [20, 20], [20, -20]],]) # w.record(1, 1) data_source.Destroy() def export_to_shape_native_grid(self, shp_folder="", shp_filename="", free_zone_only=True): """ export the grid to the shape file :param free_zone_only: :param shp_folder: :param shp_filename: """ from osgeo import ogr, osr folder = Path(shp_folder) # create the directory if does not exist if not folder.is_dir(): folder.mkdir() # set up the shapefile driver driver = ogr.GetDriverByName("ESRI Shapefile") if not shp_filename.lower().endswith(".shp"): shp_filename += ".shp" # create the data source data_source = driver.CreateDataSource(str(folder.joinpath(shp_filename))) # Projection srs = osr.SpatialReference() bmp = self.get_basemap_for_free_zone() srs.ImportFromProj4(bmp.proj4string) print(srs) print(srs.ExportToPrettyWkt()) # create the layer layer = data_source.CreateLayer("grid", srs, ogr.wkbPolygon) layer.CreateField(ogr.FieldDefn("i", ogr.OFTInteger)) layer.CreateField(ogr.FieldDefn("j", ogr.OFTInteger)) lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] # create the feature feature = ogr.Feature(layer.GetLayerDefn()) p00 = (x - self.dx / 2.0, y - self.dy / 2.0) p01 = (x - self.dx / 2.0, y + self.dy / 2.0) p11 = (x + self.dx / 2.0, y + self.dy / 2.0) p10 = (x + self.dx / 2.0, y - self.dy / 2.0) ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(*p00) ring.AddPoint(*p01) ring.AddPoint(*p11) ring.AddPoint(*p10) poly = ogr.Geometry(ogr.wkbPolygon) poly.AddGeometry(ring) feature.SetField("i", i + 1) feature.SetField("j", j + 1) feature.SetGeometry(poly) layer.CreateFeature(feature) feature.Destroy() # w.poly(parts=[[[-20, -20], [-20, 20], [20, 20], [20, -20]],]) # w.record(1, 1) data_source.Destroy() def get_basemap_for_free_zone(self, halo=None, blending=None, **kwargs): if halo is None: halo = self.halo if blending is None: blending = self.blendig lons_c, lats_c = self.get_free_zone_corners(halo=halo, blending=blending) return self.get_basemap(lons=lons_c, lats=lats_c, **kwargs) def get_basemap_using_shape_with_polygons_of_interest(self, lons, lats, shp_path=None, mask_margin=5, **kwargs): if shp_path is None: return self.get_basemap(lons=lons, lats=lats, **kwargs) reg_of_interest = get_mask(lons, lats, shp_path=shp_path) > 0 i_list, j_list = np.where(reg_of_interest) i_min = min(i_list) - mask_margin i_max = max(i_list) + mask_margin j_min = min(j_list) - mask_margin j_max = max(j_list) + mask_margin bsmap = self.get_basemap(lons=lons[i_min:i_max + 1, j_min:j_max + 1], lats=lats[i_min:i_max + 1, j_min:j_max + 1]) return bsmap, reg_of_interest def get_basemap(self, lons=None, lats=None, **kwargs): if lons is None: lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in [0, self.ni - 1]] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in [0, self.nj - 1]] latr, lonr = np.meshgrid(latr, lonr) lons = np.zeros((2, 2)) lats = np.zeros((2, 2)) for i in [-1, 0]: for j in [-1, 0]: shiftx = self.dx / 2.0 shifty = self.dy / 2.0 shiftx = -shiftx if i == 0 else shiftx shifty = -shifty if i == 0 else shifty lons[i, j], lats[i, j] = self.rll.toGeographicLonLat(lonr[i, j] + shiftx, latr[i, j] + shifty) return self.get_rot_latlon_proj_obj().get_basemap_object_for_lons_lats(lons2d=lons, lats2d=lats, **kwargs) def get_corners_in_proj_coords(self): """ :return: xxcorners, yycorners xxcorners = [[xll, xur], [xll, xur]] yycorners = [[yll, yll], [yur, yur]] """ lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in [0, self.ni - 1]] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in [0, self.nj - 1]] latr, lonr = np.meshgrid(latr, lonr) return lonr, latr def get_free_zone_corners(self, halo=10, blending=10): margin = halo + blending lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in [margin, self.ni - margin - 1]] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in [margin, self.nj - margin - 1]] latr, lonr = np.meshgrid(latr, lonr) lons = np.zeros((2, 2)) lats = np.zeros((2, 2)) for i in [-1, 0]: mulx = -1 if i >= 0 else 1 shiftx = mulx * self.dx / 2.0 for j in [-1, 0]: muly = -1 if j >= 0 else 1 shifty = muly * self.dy / 2.0 lons[i, j], lats[i, j] = self.rll.toGeographicLonLat(lonr[i, j] + shiftx, latr[i, j] + shifty) return lons, lats def get_rot_latlon_proj_obj(self): return self.rll def subgrid(self, i0, j0, di=-1, dj=-1): """ :param i0: 0-based i-index of the lower left corner of the domain :param j0: :param di: number of grid points in i direction :param dj: number of grid points in j direction """ subgr = GridConfig(rll=self.rll, dx=self.dx, dy=self.dy, xref=self.xref, yref=self.yref) if di > 0: subgr.ni = di else: subgr.ni = self.ni - i0 if dj > 0: subgr.nj = dj else: subgr.nj = self.nj - j0 subgr.iref = self.iref - i0 subgr.jref = self.jref - j0 return subgr def copy(self): return self.subgrid(0, 0, di=self.ni, dj=self.nj) def double_resolution(self): gc = GridConfig(rll=self.rll, dx=self.dx / 2.0, dy=self.dy / 2.0, xref=self.xref, yref=self.yref) gc.ni = 2 * self.ni gc.nj = 2 * self.nj gc.iref = 2 * self.iref gc.jref = 2 * self.jref gc.xref -= gc.dx / 2.0 gc.yref -= gc.dy / 2.0 return gc def double_resolution_keep_free_domain_same(self, halo_pts=10, blending_pts=10): gc = GridConfig(rll=self.rll, dx=self.dx / 2.0, dy=self.dy / 2.0, xref=self.xref, yref=self.yref) margin_pts = halo_pts + blending_pts gc.ni = 2 * (self.ni - 2 * margin_pts) + 2 * margin_pts gc.nj = 2 * (self.nj - 2 * margin_pts) + 2 * margin_pts gc.iref = 2 * (self.iref - margin_pts) + margin_pts gc.jref = 2 * (self.jref - margin_pts) + margin_pts gc.xref -= gc.dx / 2.0 gc.yref -= gc.dy / 2.0 return gc def decrease_resolution_keep_free_domain_same(self, factor, halo_pts=10, blending_pts=10): gc = GridConfig(rll=self.rll, dx=self.dx * factor, dy=self.dy * factor, xref=self.xref, yref=self.yref) margin_pts = halo_pts + blending_pts gc.ni = (self.ni - 2 * margin_pts) / factor + 2 * margin_pts gc.nj = (self.nj - 2 * margin_pts) / factor + 2 * margin_pts # Change the reference point if the new iref and jref cannot be the same new_iref = self.iref - margin_pts new_jref = self.jref - margin_pts new_iref = new_iref // factor + (new_iref % factor != 0) x00 = self.xref + self.dx * (margin_pts + 1 - self.iref) - self.dx / 2.0 new_xref = x00 + new_iref * self.dx * factor - self.dx * factor / 2.0 new_jref = new_jref // factor + (new_jref % factor != 0) y00 = self.yref + self.dy * (margin_pts + 1 - self.jref) - self.dy / 2.0 new_yref = y00 + new_jref * self.dy * factor - self.dy * factor / 2.0 gc.iref = new_iref + margin_pts gc.jref = new_jref + margin_pts gc.xref = new_xref gc.yref = new_yref gc.ni = int(gc.ni) gc.nj = int(gc.nj) return gc def move(self, di=0, dj=0): gc = GridConfig(rll=self.rll, dx=self.dx, dy=self.dy, xref=self.xref, yref=self.yref, ni=self.ni, nj=self.nj) gc.iref -= di gc.jref -= dj return gc def expand(self, di=0, dj=0): gc = GridConfig(rll=self.rll, dx=self.dx, dy=self.dy, xref=self.xref, yref=self.yref, ni=self.ni + di, nj=self.nj + dj) gc.iref = self.iref gc.jref = self.jref return gc def __str__(self): s = """ Grd_ni = {ni} , Grd_nj = {nj} , Grd_dx = {dx} , Grd_dy = {dy}, Grd_iref = {iref} , Grd_jref = {jref} , Grd_latr = {latref} , Grd_lonr = {lonref} , Grd_xlat1 = {lat1} , Grd_xlon1 = {lon1} , Grd_xlat2 = {lat2} , Grd_xlon2 = {lon2} , """.format(ni=self.ni, nj=self.nj, dx=self.dx, dy=self.dy, iref=self.iref, jref=self.jref, latref=self.yref, lonref=self.xref, lat1=self.rll.lat1, lon1=self.rll.lon1, lat2=self.rll.lat2, lon2=self.rll.lon2) return s
class GridConfig(object): projection = "rotpole" def __init__(self, **kwargs): self.dx = self.dy = kwargs.get("dx", -1) self.iref, self.jref = kwargs.get("iref", -1), kwargs.get("jref", -1) self.xref, self.yref = kwargs.get("xref", -1), kwargs.get("yref", -1) self.ni, self.nj = kwargs.get("ni", -1), kwargs.get("nj", -1) # interpolated driving data (width of the outer band in number of gridpoints) self.halo = 10 # size of the blending zone in grid points self.blendig = 10 self.rll = None if "rll" not in kwargs: self.lon1, self.lat1 = kwargs.get("lon1", None), kwargs.get("lat1", None) self.lon2, self.lat2 = kwargs.get("lon2", None), kwargs.get("lat2", None) if None not in (self.lon1, self.lon2, self.lat1, self.lat2): self.rll = RotatedLatLon(lon1=self.lon1, lon2=self.lon2, lat1=self.lat1, lat2=self.lat2) else: self.rll = kwargs.get("rll") # private fields self._center_lons_2d = None self._center_lats_2d = None @classmethod def get_default_for_resolution(cls, res=0.5): """ :param res: :rtype GridConfig """ obj = GridConfig() obj.dx = obj.dy = res if res == 0.5: obj.iref = 46 # starts from 1 not 0!! obj.jref = 42 # starts from 1 not 0!! obj.ni = 86 obj.nj = 86 elif res == 0.1: obj.iref = 142 # no need to do -1, doing it later in the formulas obj.jref = 122 obj.xref = 180 # rotated longitude obj.yref = 0 # rotated latitude # projection parameters obj.lon1 = -68.0 obj.lat1 = 52.0 obj.lon2 = 16.65 obj.lat2 = 0.0 obj.ni = 260 obj.nj = 260 return obj def export_to_shape(self, shp_folder="", shp_filename="", free_zone_only=True, export_mask=None, shape_fields=None): """ export the grid to the shape file :param export_mask: Mask to specify exactly which gridcells should be exported :param free_zone_only: :param shp_folder: :param shp_filename: """ import shapefile as shp w = shp.Writer(shp.POLYGON) w.field("i", fieldType="I") w.field("j", fieldType="I") field_names_in_order = ["i", "j"] if shape_fields is not None: for field_name, field in shape_fields.items(): w.field(field_name, *field.type_of_shp_field) field_names_in_order.append(field_name) if isinstance(shp_folder, str): folder = Path(shp_folder) else: folder = shp_folder # create the directory if does not exist if not folder.is_dir(): folder.mkdir() lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 if export_mask is None: export_mask = np.ones((self.ni, self.nj), dtype=bool) for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] if not export_mask[i, j]: continue p00 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y - self.dy / 2.0) p01 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y + self.dy / 2.0) p11 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y + self.dy / 2.0) p10 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y - self.dy / 2.0) w.poly(parts=[[p00, p01, p11, p10]]) if shape_fields is None: w.record(i + 1, j + 1) else: record_fields = {} record_fields["i"] = i + 1 record_fields["j"] = j + 1 for field_name, field in shape_fields.items(): record_fields[field_name] = field[i, j] w.record( *[record_fields[key] for key in field_names_in_order]) # w.poly(parts=[[[-20, -20], [-20, 20], [20, 20], [20, -20]],]) # w.record(1, 1) w.save(str(folder.joinpath(shp_filename))) def export_to_shape_fiona(self, shp_folder="", shp_filename="", free_zone_only=True, export_mask=None, shape_fields=None): """ export the grid to the shape file using fiona since pyshp was not compatible with arcgis :param export_mask: Mask to specify exactly which gridcells should be exported :param free_zone_only: :param shp_folder: :param shp_filename: """ from fiona.crs import from_epsg, from_string import fiona proj = from_epsg(4326) # proj = from_epsg(4269) # proj = from_string("+units=m +lon_0=-97.0 +o_lon_p=180.0 +R=6370997.0 +o_proj=longlat +proj=ob_tran +o_lat_p=42.5") print(proj) print(dir(proj)) # proj = from_epsg(900913) if isinstance(shp_folder, str): folder = Path(shp_folder) else: folder = shp_folder # create the directory if does not exist if not folder.is_dir(): folder.mkdir() schema = { "geometry": "Polygon", "properties": OrderedDict([("i", "int"), ("j", "int")]) } if shape_fields is not None: # additional fields for field_name, field in shape_fields.items(): schema["properties"][field_name] = field.type_of_shp_field with fiona.open(str(folder.joinpath(shp_filename)), mode="w", driver="ESRI Shapefile", crs=proj, schema=schema) as output: lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 if export_mask is None: export_mask = np.ones((self.ni, self.nj), dtype=bool) polygons = [] lake_fractions = [] for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] if not export_mask[i, j]: continue p00 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y - self.dy / 2.0) p01 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y + self.dy / 2.0) p11 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y + self.dy / 2.0) p10 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y - self.dy / 2.0) # p00 = (x - self.dx / 2.0, y - self.dy / 2.0) # p01 = (x - self.dx / 2.0, y + self.dy / 2.0) # p11 = (x + self.dx / 2.0, y + self.dy / 2.0) # p10 = (x + self.dx / 2.0, y - self.dy / 2.0) poly = Polygon(shell=[p00, p01, p11, p10, p00]) props = OrderedDict([("i", i + 1), ("j", j + 1)]) polygons.append(PolygonPatch(poly)) if shape_fields is not None: lake_fractions.append(shape_fields["lkfr"][i, j]) for field_name, field in shape_fields.items(): converter = float if field.type_of_shp_field.startswith( "float") else int props[field_name] = converter(field[i, j]) output.write({ "geometry": mapping(poly), "properties": props }) # plot the gridcells with basemap # pcol = PatchCollection(polygons, cmap="bone_r") # pcol.set_array(np.array(lake_fractions)) # import matplotlib.pyplot as plt # bmp = self.get_basemap_for_free_zone(resolution="l") # fig = plt.figure() # ax = fig.add_subplot(111) # bmp.ax = ax # ax.add_collection(pcol) # bmp.drawcoastlines(ax=ax) # plt.show() def export_to_shape_ogr(self, shp_folder="", shp_filename="", free_zone_only=True): """ export the grid to the shape file :param free_zone_only: :param shp_folder: :param shp_filename: """ from osgeo import ogr, osr folder = Path(shp_folder) # create the directory if does not exist if not folder.is_dir(): folder.mkdir() # set up the shapefile driver driver = ogr.GetDriverByName("ESRI Shapefile") if not shp_filename.lower().endswith(".shp"): shp_filename += ".shp" # create the data source data_source = driver.CreateDataSource( str(folder.joinpath(shp_filename))) srs = osr.SpatialReference() srs.ImportFromWkt(osr.SRS_WKT_WGS84) print(srs) print(srs.ExportToPrettyWkt()) # create the layer layer = data_source.CreateLayer("grid", srs, ogr.wkbPolygon) layer.CreateField(ogr.FieldDefn("i", ogr.OFTInteger)) layer.CreateField(ogr.FieldDefn("j", ogr.OFTInteger)) lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] # create the feature feature = ogr.Feature(layer.GetLayerDefn()) p00 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y - self.dy / 2.0) p01 = self.rll.toGeographicLonLat(x - self.dx / 2.0, y + self.dy / 2.0) p11 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y + self.dy / 2.0) p10 = self.rll.toGeographicLonLat(x + self.dx / 2.0, y - self.dy / 2.0) ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(*p00) ring.AddPoint(*p01) ring.AddPoint(*p11) ring.AddPoint(*p10) poly = ogr.Geometry(ogr.wkbPolygon) poly.AddGeometry(ring) feature.SetField("i", i + 1) feature.SetField("j", j + 1) feature.SetGeometry(poly) layer.CreateFeature(feature) feature.Destroy() # w.poly(parts=[[[-20, -20], [-20, 20], [20, 20], [20, -20]],]) # w.record(1, 1) data_source.Destroy() def export_to_shape_native_grid(self, shp_folder="", shp_filename="", free_zone_only=True): """ export the grid to the shape file :param free_zone_only: :param shp_folder: :param shp_filename: """ from osgeo import ogr, osr folder = Path(shp_folder) # create the directory if does not exist if not folder.is_dir(): folder.mkdir() # set up the shapefile driver driver = ogr.GetDriverByName("ESRI Shapefile") if not shp_filename.lower().endswith(".shp"): shp_filename += ".shp" # create the data source data_source = driver.CreateDataSource( str(folder.joinpath(shp_filename))) # Projection srs = osr.SpatialReference() bmp = self.get_basemap_for_free_zone() srs.ImportFromProj4(bmp.proj4string) print(srs) print(srs.ExportToPrettyWkt()) # create the layer layer = data_source.CreateLayer("grid", srs, ogr.wkbPolygon) layer.CreateField(ogr.FieldDefn("i", ogr.OFTInteger)) layer.CreateField(ogr.FieldDefn("j", ogr.OFTInteger)) lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] margin = 0 if free_zone_only: margin = self.blendig + self.halo start_i = margin start_j = margin end_i = self.ni - margin - 1 end_j = self.nj - margin - 1 for i in range(start_i, end_i + 1): x = lonr[i] for j in range(start_j, end_j + 1): y = latr[j] # create the feature feature = ogr.Feature(layer.GetLayerDefn()) p00 = (x - self.dx / 2.0, y - self.dy / 2.0) p01 = (x - self.dx / 2.0, y + self.dy / 2.0) p11 = (x + self.dx / 2.0, y + self.dy / 2.0) p10 = (x + self.dx / 2.0, y - self.dy / 2.0) ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(*p00) ring.AddPoint(*p01) ring.AddPoint(*p11) ring.AddPoint(*p10) poly = ogr.Geometry(ogr.wkbPolygon) poly.AddGeometry(ring) feature.SetField("i", i + 1) feature.SetField("j", j + 1) feature.SetGeometry(poly) layer.CreateFeature(feature) feature.Destroy() # w.poly(parts=[[[-20, -20], [-20, 20], [20, 20], [20, -20]],]) # w.record(1, 1) data_source.Destroy() def get_basemap_for_free_zone(self, halo=None, blending=None, **kwargs): if halo is None: halo = self.halo if blending is None: blending = self.blendig lons_c, lats_c = self.get_free_zone_corners(halo=halo, blending=blending) return self.get_basemap(lons=lons_c, lats=lats_c, **kwargs) def get_basemap_using_shape_with_polygons_of_interest( self, lons, lats, shp_path=None, mask_margin=5, **kwargs): if shp_path is None: return self.get_basemap(lons=lons, lats=lats, **kwargs) reg_of_interest = get_mask(lons, lats, shp_path=shp_path) > 0 i_list, j_list = np.where(reg_of_interest) i_min = min(i_list) - mask_margin i_max = max(i_list) + mask_margin j_min = min(j_list) - mask_margin j_max = max(j_list) + mask_margin bsmap = self.get_basemap(lons=lons[i_min:i_max + 1, j_min:j_max + 1], lats=lats[i_min:i_max + 1, j_min:j_max + 1], **kwargs) return bsmap, reg_of_interest def get_basemap(self, lons=None, lats=None, **kwargs): if lons is None: lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in [0, self.ni - 1]] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in [0, self.nj - 1]] latr, lonr = np.meshgrid(latr, lonr) lons = np.zeros((2, 2)) lats = np.zeros((2, 2)) for i in [-1, 0]: for j in [-1, 0]: shiftx = self.dx / 2.0 shifty = self.dy / 2.0 shiftx = -shiftx if i == 0 else shiftx shifty = -shifty if i == 0 else shifty lons[i, j], lats[i, j] = self.rll.toGeographicLonLat( lonr[i, j] + shiftx, latr[i, j] + shifty) return self.get_rot_latlon_proj_obj().get_basemap_object_for_lons_lats( lons2d=lons, lats2d=lats, **kwargs) def get_corners_in_proj_coords(self): """ :return: xxcorners, yycorners xxcorners = [[xll, xur], [xll, xur]] yycorners = [[yll, yll], [yur, yur]] """ lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in [0, self.ni - 1]] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in [0, self.nj - 1]] latr, lonr = np.meshgrid(latr, lonr) return lonr, latr def get_free_zone_corners(self, halo=10, blending=10): margin = halo + blending lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in [margin, self.ni - margin - 1]] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in [margin, self.nj - margin - 1]] latr, lonr = np.meshgrid(latr, lonr) lons = np.zeros((2, 2)) lats = np.zeros((2, 2)) for i in [-1, 0]: mulx = -1 if i >= 0 else 1 shiftx = mulx * self.dx / 2.0 for j in [-1, 0]: muly = -1 if j >= 0 else 1 shifty = muly * self.dy / 2.0 lons[i, j], lats[i, j] = self.rll.toGeographicLonLat( lonr[i, j] + shiftx, latr[i, j] + shifty) return lons, lats def get_rot_latlon_proj_obj(self): return self.rll def subgrid(self, i0, j0, di=-1, dj=-1): """ :param i0: 0-based i-index of the lower left corner of the domain :param j0: :param di: number of grid points in i direction :param dj: number of grid points in j direction """ subgr = GridConfig(rll=self.rll, dx=self.dx, dy=self.dy, xref=self.xref, yref=self.yref) if di > 0: subgr.ni = di else: subgr.ni = self.ni - i0 if dj > 0: subgr.nj = dj else: subgr.nj = self.nj - j0 subgr.iref = self.iref - i0 subgr.jref = self.jref - j0 return subgr def copy(self): return self.subgrid(0, 0, di=self.ni, dj=self.nj) def double_resolution(self): gc = GridConfig(rll=self.rll, dx=self.dx / 2.0, dy=self.dy / 2.0, xref=self.xref, yref=self.yref) gc.ni = 2 * self.ni gc.nj = 2 * self.nj gc.iref = 2 * self.iref gc.jref = 2 * self.jref gc.xref -= gc.dx / 2.0 gc.yref -= gc.dy / 2.0 return gc def double_resolution_keep_free_domain_same(self, halo_pts=10, blending_pts=10): gc = GridConfig(rll=self.rll, dx=self.dx / 2.0, dy=self.dy / 2.0, xref=self.xref, yref=self.yref) margin_pts = halo_pts + blending_pts gc.ni = 2 * (self.ni - 2 * margin_pts) + 2 * margin_pts gc.nj = 2 * (self.nj - 2 * margin_pts) + 2 * margin_pts gc.iref = 2 * (self.iref - margin_pts) + margin_pts gc.jref = 2 * (self.jref - margin_pts) + margin_pts gc.xref -= gc.dx / 2.0 gc.yref -= gc.dy / 2.0 return gc def decrease_resolution_keep_free_domain_same(self, factor, halo_pts=10, blending_pts=10): gc = GridConfig(rll=self.rll, dx=self.dx * factor, dy=self.dy * factor, xref=self.xref, yref=self.yref) margin_pts = halo_pts + blending_pts gc.ni = (self.ni - 2 * margin_pts) / factor + 2 * margin_pts gc.nj = (self.nj - 2 * margin_pts) / factor + 2 * margin_pts # Change the reference point if the new iref and jref cannot be the same new_iref = self.iref - margin_pts new_jref = self.jref - margin_pts new_iref = new_iref // factor + (new_iref % factor != 0) x00 = self.xref + self.dx * (margin_pts + 1 - self.iref) - self.dx / 2.0 new_xref = x00 + new_iref * self.dx * factor - self.dx * factor / 2.0 new_jref = new_jref // factor + (new_jref % factor != 0) y00 = self.yref + self.dy * (margin_pts + 1 - self.jref) - self.dy / 2.0 new_yref = y00 + new_jref * self.dy * factor - self.dy * factor / 2.0 gc.iref = new_iref + margin_pts gc.jref = new_jref + margin_pts gc.xref = new_xref gc.yref = new_yref gc.ni = int(gc.ni) gc.nj = int(gc.nj) return gc def move(self, di=0, dj=0): gc = GridConfig(rll=self.rll, dx=self.dx, dy=self.dy, xref=self.xref, yref=self.yref, ni=self.ni, nj=self.nj) gc.iref -= di gc.jref -= dj return gc def expand(self, di=0, dj=0): gc = GridConfig(rll=self.rll, dx=self.dx, dy=self.dy, xref=self.xref, yref=self.yref, ni=self.ni + di, nj=self.nj + dj) gc.iref = self.iref gc.jref = self.jref return gc def __str__(self): s = """ Grd_ni = {ni} , Grd_nj = {nj} , Grd_dx = {dx} , Grd_dy = {dy}, Grd_iref = {iref} , Grd_jref = {jref} , Grd_latr = {latref} , Grd_lonr = {lonref} , Grd_xlat1 = {lat1} , Grd_xlon1 = {lon1} , Grd_xlat2 = {lat2} , Grd_xlon2 = {lon2} , """.format(ni=self.ni, nj=self.nj, dx=self.dx, dy=self.dy, iref=self.iref, jref=self.jref, latref=self.yref, lonref=self.xref, lat1=self.rll.lat1, lon1=self.rll.lon1, lat2=self.rll.lat2, lon2=self.rll.lon2) return s def __hash__(self): return hash(str(self).lower()) def __eq__(self, other): if other is None: return False return str(self).lower() == str(other).lower() def get_lons_and_lats_of_gridpoint_centers(self): """ :return: lons and lats corresponding to the gridpoint centers """ if self._center_lons_2d is not None: return self._center_lons_2d, self._center_lats_2d lonr = [(i - (self.iref - 1)) * self.dx + self.xref for i in range(self.ni)] latr = [(j - (self.jref - 1)) * self.dy + self.yref for j in range(self.nj)] lons = np.zeros((self.ni, self.nj)) lats = np.zeros_like(lons) for i, lonri in enumerate(lonr): for j, latrj in enumerate(latr): lons[i, j], lats[i, j] = self.rll.toGeographicLonLat(lonri, latrj) # Save for re-use self._center_lons_2d = lons self._center_lats_2d = lats return lons, lats