HydroGrid.py 6.1 KB
Newer Older
1 2 3 4 5 6 7 8
#
# Reads ans manages the model grid
#
import numpy as np
from netCDF4 import Dataset
# Doc : https://spacetelescope.github.io/spherical_geometry/api/spherical_geometry.polygon.SphericalPolygon.html
from spherical_geometry import polygon
import RPPtools as RPP
9
import os 
10 11 12 13
#
import configparser
config=configparser.ConfigParser()
config.read("run.def")
14
EarthRadius=config.getfloat("OverAll", "EarthRadius", fallback=6370000.0)
15 16 17 18 19 20 21
#
import getargs
log_master, log_world = getargs.getLogger(__name__)
INFO, DEBUG, ERROR = log_master.info, log_master.debug, log_world.error
INFO_ALL, DEBUG_ALL = log_world.info, log_world.debug
#
def getbox(ncdf, corners) :
22 23 24 25 26 27
    # Add a few points to tbe box to make sure to cover everything
    halo_pts=2
    ii=[np.argmin(abs(ncdf.variables["nav_lon"][0,:]-np.min(corners[0][:]))),
        np.argmin(abs(ncdf.variables["nav_lon"][0,:]-np.max(corners[0][:])))]
    jj=[np.argmin(abs(ncdf.variables["nav_lat"][:,0]-np.min(corners[1][:]))),
        np.argmin(abs(ncdf.variables["nav_lat"][:,0]-np.max(corners[1][:])))]
28

29
    return min(ii)-halo_pts, max(ii)+halo_pts, min(jj)-halo_pts, max(jj)+halo_pts
30 31 32 33 34
#
# Get the corners for a regular lat/lon grid
#
def corners(lon, lat) :
    jjm,iim = lon.shape
35
    #
36 37
    hdlon=np.mean(np.abs(np.diff(lon[0,:])))
    hdlat=np.mean(np.abs(np.diff(lat[:,0])))
38
    #
Anthony's avatar
Anthony committed
39
    cornersll = [RPP.boxit(np.array([lon[j,i], lat[j,i]]), hdlon, hdlat, 2) for i in range(iim) for j in range(jjm)]
40 41 42 43 44
    Llons = [[p[0] for p in boxll] for boxll in cornersll]
    Llats = [[p[1] for p in boxll] for boxll in cornersll]
    index = [[j,i] for i in range(iim) for j in range(jjm)]
    centersll = [[lon[j,i], lat[j,i]] for j,i in index]
    cornerspoly = [ polygon.SphericalPolygon.from_lonlat(lons, lats, center=cent) for lons, lats, cent in zip(Llons, Llats, centersll)]
Anthony's avatar
Anthony committed
45
    radiusll = [RPP.maxradius(np.array(cent), np.array(lons), np.array(lats)) for cent, lons, lats in zip(centersll,Llons,Llats)]
46
    #
47
    return cornersll, cornerspoly, centersll, radiusll, index
48
#
49
def gather(x, index, default = 0) :
50 51
    y=[]
    for ia in index :
52 53 54 55
        if (ia[:,0] == [-1, -1]).all():
            y.append([default])
        else:
            y.append(list(x[ia[0,i],ia[1,i]] for i in range(ia.shape[1]) ))
56 57 58 59 60 61 62 63 64 65 66
    return y
#
def getattrcontaining(nc, varname, substr) :
    att=[]
    for s in nc.variables[varname].ncattrs() :
        if s.lower().find(substr) >= 0 :
            att.append(nc.variables[varname].getncattr(s))

    return att
#
class HydroGrid :
67
    def __init__(self, lolacorners, wfile) :
68
        #
69 70 71
        self.source=config.get("OverAll", "HydroFile")
        INFO("Opening in HydroGrid : "+self.source)
        self.ncfile=Dataset(self.source,'r')
72 73 74 75 76 77 78
        istr, iend, jstr, jend = getbox(self.ncfile, lolacorners)
        self.box=[istr, iend, jstr, jend]
        self.lon=np.copy(self.ncfile.variables["nav_lon"][jstr:jend,istr:iend])
        self.lat=np.copy(self.ncfile.variables["nav_lat"][jstr:jend,istr:iend])
        self.jjm,self.iim = self.lon.shape
        DEBUG("# Range Lon :"+str(np.min(self.lon))+" -- "+str(np.max(self.lon)))
        DEBUG("# Range Lat :"+str(np.min(self.lat))+" -- "+str(np.max(self.lat)))
79 80 81
        #
        if not os.path.exists(wfile): 
            self.polyll, self.polylist, self.centers, self.radius, self.index = corners(self.lon, self.lat)
82 83

    def select(self, c, r) :
Anthony's avatar
Anthony committed
84
        indices = [i for i in range(len(self.centers)) if (RPP.loladist(np.array(c),np.array(self.centers[i])) <= r+self.radius[i])]
85
        return indices
86 87 88 89

class HydroData :
    def __init__(self, nf, box, index) :
        istr, iend, jstr, jend = box[:]
90
        self.trip=gather(nf.variables["trip"][jstr:jend,istr:iend].astype(np.float32), index, 97)
91 92
        self.tripdesc=nf.variables["trip"].long_name
        #
93
        self.basins=gather(nf.variables["basins"][jstr:jend,istr:iend], index, 999)
94 95 96 97 98 99
        self.basinsdesc=nf.variables["basins"].long_name
        att = getattrcontaining(nf, "basins", "max")
        if len(att) > 0 :
            self.basinsmax=att[0]
        else :
            INFO("We need to scan full file to find maximum number of basins")
100 101
            # This variable seems not to be used further
            self.basinsmax = part.domainmax(np.ma.max(ma.masked_where(self.basins < 1.e10, self.basins)))
102
        #
103
        self.topoind=gather(nf.variables["topoind"][jstr:jend,istr:iend].astype(np.float32), index, 10)
104 105 106 107 108 109 110 111 112
        self.topoinddesc=nf.variables["topoind"].long_name
        att = getattrcontaining(nf, "topoind", "min")
        if len(att) > 0 :
            self.topoindmin=att[0]
        else :
            INFO("We need to scan full file to find minimum topoind over domain")
            self.topoindmin=np.min(np.where(nf.variables["topoind"][:,:] <  1.e15))
        #
        #
113
        self.topoindh=gather(nf.variables["topoind_h"][jstr:jend,istr:iend].astype(np.float32), index, 10)
114 115 116 117 118 119 120 121
        self.topoindhdesc=nf.variables["topoind_h"].long_name
        att = getattrcontaining(nf, "topoind_h", "min")
        if len(att) > 0 :
            self.topoindhmin=att[0]
        else :
            INFO("We need to scan full file to find minimum topoind_h over domain")
            self.topoindhmin=np.min(np.where(nf.variables["topoind_h"][:,:] <  1.e15))
        #
122
        self.disto=gather(nf.variables["disto"][jstr:jend,istr:iend].astype(np.float32), index, 0)
123 124
        self.distodesc=nf.variables["disto"].long_name
        #
125
        self.fac=gather(nf.variables["fac"][jstr:jend,istr:iend].astype(np.float32), index, 0)
126
        self.facdesc=nf.variables["fac"].long_name
127 128
        #
        if "orog" in nf.variables.keys():
129
            self.orog = gather(nf.variables["orog"][jstr:jend,istr:iend].astype(np.float32), index, 0)
130 131 132 133 134
            self.orogdesc=nf.variables["orog"].long_name
        else:
            self.orog = gather(np.zeros((jend-jstr,iend-istr)).astype(np.float32), index)
        #
        if "floodplains" in nf.variables.keys():
135
            self.floodplains = gather(nf.variables["floodplains"][jstr:jend,istr:iend].astype(np.float32), index, 0)
136 137 138
            self.floodplainsdesc=nf.variables["floodplains"].long_name
        else:
            self.floodplains = gather(np.zeros((jend-jstr,iend-istr)).astype(np.float32), index)