示例#1
0
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()
示例#3
0
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
示例#4
0
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
示例#5
0
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()
示例#6
0
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
示例#7
0
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()
示例#8
0
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
示例#9
0
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
示例#10
0
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