Source code for pypago.toolsec

''' Toolbox for the definition of gridded sections '''

import numpy as np
from sample_param import ee
try:
    from param import ee
except:
    pass

[docs]def secingrid(fromi, fromj, toi, toj): """ Calculates the sequence of grid points to go from (`fromj`, `fromi`) to (`toj`, `toi`), by following the straight line that joints the two end points. Adjacent grid points have one side in common. :param int fromi: start i index :param int fromj: start j index :param int toi: end i index :param int toj: end i index """ # this offset is only for consistency with the |matlab| veci indices off = 1 fromi = np.atleast_1d(fromi) + off fromj = np.atleast_1d(fromj) + off toi = np.atleast_1d(toi) + off toj = np.atleast_1d(toj) + off if toi - fromi == 0: vecj = np.linspace(fromj, toj, np.abs(toj - fromj) + 1).astype(np.int) veci = fromi * np.ones(len(vecj)) else: if toj - fromj == 0: veci = np.linspace(fromi, toi, np.abs(toi - fromi) + 1).astype(np.int) vecj = fromj * np.ones(len(veci)) else: veci = np.copy(fromi) vecj = np.copy(fromj) a = (toj - fromj) / ((toi - fromi).astype(np.float)) b = toj - toi*a while not ((veci[-1] == toi) & (vecj[-1] == toj)): newi = veci[-1] + np.sign(toi - fromi) newj = vecj[-1] + np.sign(toj - fromj) y = a * newi + b x = (newj - b) / (a.astype(np.float)) if np.abs(x - veci[-1]) >= np.abs(y - vecj[-1]): veci = np.append(veci, newi) vecj = np.append(vecj, vecj[-1]) else: veci = np.append(veci, veci[-1]) vecj = np.append(vecj, newj) # correction back to python (removing off=1) veci = veci.astype(np.int) - off vecj = vecj.astype(np.int) - off return vecj, veci
[docs]def lengthinsec(veci, vecj, faces, dw, dn): """ Determines the length of section edges depending on the cell face. :param numpy.array veci: i index of the section grid cells :param numpy.array vecj: j index of the section grid cells :param numpy.array faces: face of the section grid cells :param numpy.array dw: scale factors on the western faces of the model cells :param numpy.array dn: scale factors on the northern faces of the model cells :return: length along the section """ lengthvect = np.empty(len(veci)) for l in xrange(0, len(veci)): if faces[l] == 'N': lengthvect[l] = np.squeeze(dn[vecj[l], veci[l]]) elif faces[l] == 'W': lengthvect[l] = np.squeeze(dw[vecj[l], veci[l]]) return lengthvect
[docs]def locingrid(lon, lat, matlon, matlat): """ Locates the nearest grid point (lon,lat) within the 2D grid defined by the matlon and matlat arrays. :param numpy.array lon: Array that contains the longitude of the sections' points :param numpy.array lat: Array that contains the latitude of the sections' points :param numpy.array matlon: Matrix that contains the longitude of the model :param numpy.array matlon: Matrix that contains the latitude of the model :return: the j and i indexes that correspond to the section endpoints on the grid :rtype: list """ a = np.max(np.abs(matlon[1:, :] - matlon[:-1, :])) b = np.max(np.abs(matlon[:, 1:] - matlon[:, :-1])) step_x = np.max([a, b]) c = np.max(np.abs(matlat[1:, :] - matlat[:-1, :])) d = np.max(np.abs(matlat[:, 1:] - matlat[:, :-1])) step_y = np.max([c, d]) vecj = np.empty(len(lon)) veci = np.empty(len(lon)) for l in xrange(0, len(lon)): if lon[l] < np.min(matlon): lon[l] = lon[l] + 360 if lon[l] > np.max(matlon): lon[l] = lon[l] - 360 [j, i] = np.nonzero((matlon <= lon[l] + step_x) & (matlon >= lon[l] - step_x) & (matlat <= lat[l] + step_y) & (matlat >= lat[l] - step_y)) if len(j) > 1: dis = np.empty(len(j)) for ii in xrange(0, len(j)): dis[ii] = np.abs(distance(lat[l], lon[l], matlat[j[ii], i[ii]], matlon[j[ii], i[ii]], ee)) ind = np.argmin(dis) elif len(j) == 1: ind = 0 else: message = 'Problem in locingrid. Please check that ' message += '%s N and %s E are within grid boundaries.' %(lat[l], lon[l]) raise IOError(message) vecj[l] = j[ind] veci[l] = i[ind] veci = veci.astype(np.int) vecj = vecj.astype(np.int) return vecj, veci
[docs]def distance(lat1, lon1, lat2, lon2, geoid): """ Computes the distance between the points (lon1, lat1) and (lon2, lat2). This function used the :py:func:`mpl_toolkits.basemap.pyproj.Geod.inv` function. :param float lat1: latitude of the first point :param float lon1: longitude of the first point :param float lat2: latitude of the second point :param float lon2: longitude of the second point :param mpl_toolkits.basemap.pyproj.Geod geoid: :py:class:`mpl_toolkits.basemap.pyproj.Geod` object used to compute the distance :return: distance between the two points :rtype: float """ output = geoid.inv(lon1, lat1, lon2, lat2) return output[-1]
[docs]def areainsec(veci, vecj, faces, areaw, arean): """ Determines the area of a |pago| section given its indexes and faces :param numpy.array veci: i-indexes of the section :param numpy.array vecj: j-indexes of the section :param numpy.array faces: array that contain the faces of the section ('W' or 'N') :param numpy.array areaW: 3D-array (z, lat, lon) that contains the area of the western faces of the grid cells :param numpy.array areaN: 3D-array (z, lat, lon) that contains the area of the northern faces of the grid cells :return: 2D (z, l) area of the |pago| section. If faces[p] == 'N', area[:, p] = areaN[:, vecj[l], veci[l]] :rtype: numpy.array """ a = arean.shape[0] areavect = np.zeros((a, len(veci))) for l in xrange(0, len(veci)): if faces[l] == 'N': areavect[:, l] = arean[:, vecj[l], veci[l]] elif faces[l] == 'W': areavect[:, l] = areaw[:, vecj[l], veci[l]] return areavect
[docs]def consec(veci1, vecj1, faces1, orient1, veci2, vecj2, faces2, orient2): """ Function that joins multiple segments belonging to one section. At first does a preprocessing of the file and then calls the :py:func:`pypago.sec._consec._consec` function """ # barrier.n --- modified 2015-08-18 # better "syntax" # correction of a huge bug: any replaced by all # correction nbarrier: should be < instead of <= if np.all(veci2 < veci1[-2]): [faces, veci, vecj, orient] = conseclr2(veci2[::-1], vecj2[::-1], faces2[::-1], orient2[::-1], veci1[::-1], vecj1[::-1], faces1[::-1], orient1[::-1]) finalfaces = faces[::-1] finalveci = veci[::-1] finalvecj = vecj[::-1] finalorient = orient[::-1] else: [finalfaces, finalveci, finalvecj, finalorient] = \ conseclr2(veci1, vecj1, faces1, orient1, veci2, vecj2, faces2, orient2) return finalfaces, finalveci, finalvecj, finalorient
[docs]def conseclr2(veci1, vecj1, faces1, orient1, veci2, vecj2, faces2, orient2): """ Function that joins multiple segments belonging to one section. """ # JD PAGO WHOI if faces1[-1] == 'N': # vec1 ends with a north face if faces2[0] == 'N': # vec2 starts with a north face veci2 = veci2[1:] vecj2 = vecj2[1:] faces2 = faces2[1:] orient2 = orient2[1:] if veci1[-2] <= veci1[-1]: if veci2[0] <= veci1[-1]: veci1 = veci1[:-1] vecj1 = vecj1[:-1] faces1 = faces1[:-1] orient1 = orient1[:-1] while (veci2[0] == veci1[-1]) & (vecj2[0] == vecj1[-1]): veci2 = veci2[1:] vecj2 = vecj2[1:] faces2 = faces2[1:] orient2 = orient2[1:] veci1 = veci1[:-1] vecj1 = vecj1[:-1] faces1 = faces1[:-1] orient1 = orient1[:-1] else: if veci2[0] >= veci1[-1]: veci1 = veci1[:-1] vecj1 = vecj1[:-1] faces1 = faces1[:-1] orient1 = orient1[:-1] while (veci2[1-1] == veci1[-1]) & (vecj2[0] == vecj1[-1]): veci2 = veci2[1:] vecj2 = vecj2[1:] faces2 = faces2[1:] orient2 = orient2[1:] veci1 = veci1[:-1] vecj1 = vecj1[:-1] faces1 = faces1[:-1] orient1 = orient1[:-1] else: # vec2 starts with a west face # vec2 starts with a west face then a north face at the same point if (faces2[1] == 'N') & (veci2[1] == veci2[0]) & (vecj2[1] == vecj2[0]): veci2 = veci2[2:] vecj2 = vecj2[2:] faces2 = faces2[2:] orient2 = orient2[2:] # vec2 starts with a west face then west face again # (to the north or to the south) else: veci1 = veci1[:-1] vecj1 = vecj1[:-1] faces1 = faces1[:-1] orient1 = orient1[:-1] if vecj2[1] > vecj2[0]: veci2 = veci2[1:] vecj2 = vecj2[1:] faces2 = faces2[1:] orient2 = orient2[1:] while (veci1[-1] == veci2[0]) & (vecj1[-1] == vecj2[0]): veci1 = veci1[:-1] vecj1 = vecj1[:-1] faces1 = faces1[:-1] orient1 = orient1[:-1] veci2 = veci2[1:] vecj2 = vecj2[1:] faces2 = faces2[1:] orient2 = orient2[1:] else: if (veci1[-1] == veci2[0]) & (vecj1[-1] == vecj2[0]): veci1 = veci1[:-1] vecj1 = vecj1[:-1] faces1 = faces1[:-1] orient1 = orient1[:-1] finalveci = np.append(veci1, veci2) finalvecj = np.append(vecj1, vecj2) finalfaces = np.append(faces1, faces2) finalorient = np.append(orient1, orient2) return finalfaces, finalveci, finalvecj, finalorient
[docs]def nodouble(veci, vecj): """ Function that removes the double in the veci and vecj arrays of a section. The output list are first initialised by the first elements of the veci and vecj arrays. Then if the n-1th elements is different from the nth element, it is added to the output list :param numpy.array veci: i indexes of the section :param numpy.array vecj: j indexes of the section :return: the veci and vecj indexes but with the double elements :rtype: list """ newveci = veci[0] newvecj = vecj[0] for l in xrange(1, len(veci)): if not (veci[l] == veci[l-1]) & (vecj[l] == vecj[l-1]): newvecj = np.append(newvecj, vecj[l]) newveci = np.append(newveci, veci[l]) return newvecj, newveci
[docs]def correct_sections(sec, secname, offset, position): """ Function that allows to correct section staircases. Especially useful in order to correct sections' junctions. It extracts the section variables (`veci`, `vecj`, etc) along the length coordinates, from `offset` to `end` or from `start` to `offset`, depending on the value of `position` argument. :param list sec: section list that contains the |pypago| objects, containing the veci, vecj, vect, ... obtained from the :py:func:`pypago.sec.finalisesections` :param type secname: section points to correct :param int offset: number of points to remove :param str position: {'start','end'} whether we remove the first (position='start') or last (position='end') points. """ nw = findsecnum(sec, secname) if position == 'end': sec[nw].veci = sec[nw].veci[:-offset] sec[nw].vecj = sec[nw].vecj[:-offset] sec[nw].vect = sec[nw].vect[:, :, :-offset] sec[nw].vecs = sec[nw].vecs[:, :, :-offset] sec[nw].vecv = sec[nw].vecv[:, :, :-offset] sec[nw].faces = sec[nw].faces[:-offset] sec[nw].orient = sec[nw].orient[:-offset] sec[nw].areavect = sec[nw].areavect[:, :-offset] sec[nw].depthvect = sec[nw].depthvect[:, :-offset] sec[nw].lvect = sec[nw].lvect[:-offset] sec[nw].lengthvect = sec[nw].lengthvect[:-offset] else: sec[nw].veci = sec[nw].veci[offset:] sec[nw].vecj = sec[nw].vecj[offset:] sec[nw].vect = sec[nw].vect[:, :, offset:] sec[nw].vecs = sec[nw].vecs[:, :, offset:] sec[nw].vecv = sec[nw].vecv[:, :, offset:] sec[nw].faces = sec[nw].faces[offset:] sec[nw].orient = sec[nw].orient[offset:] sec[nw].lengthvect = sec[nw].lengthvect[offset:] sec[nw].lvect = sec[nw].lvect[offset:] sec[nw].areavect = sec[nw].areavect[:, offset:] sec[nw].depthvect = sec[nw].depthvect[:, offset:] return sec
[docs]def facesinsec(veci, vecj, dire): """ Function which defines the sequence of faces that allow to join two section endpoints (i.e for a segment) By convention, we tend to favor the north and west side of each grid cell as a 'face' of a sequence of gridpoints. `veci` and `vecj` are reconstructed to i) drop the points which faces are not used, and ii) double the grid points which faces are used twice. Faces is a vector of letters: - N means that the north face is to be used - W means that the west face is to be used Orientation is a vector of +1 or -1 that shall be applied to velocities in order to make sure that the transport is integrated in the direction dir, which is a two letter vector: NE, NW, SE or SW. Calculation assumes that vectors are originally pointing toward N or E. :param numpy.array veci: i index determined from :py:func:`pypago.sec._secingrid` :param numpy.array vecj: j index determined from :py:func:`pypago.sec._secingrid` :param str dir: orientation of the segment :return: a tuple that contains the sequence of faces, i and j indexes and the orientation for each face :rtype: tuple :raises ValueError: if either veci or vecj are not monotonous :raises IndexError: if length of veci is 1 """ if len(veci) == 1: logger.error('only one point in sequence; no face should be used') raise IndexError if not monotonous(veci): logger.error('sequence veci must be monotonous') raise ValueError if not monotonous(vecj): logger.error('sequence vecj must be monotonous') raise ValueError if veci[-1] == veci[0]: newveci = np.copy(veci) newvecj = np.copy(vecj) faces = ['W'] * len(newveci); else: changedir = 0 if veci[-1] < veci[0]: veci = veci[::-1] vecj = vecj[::-1] changedir = 1 indvec = 0 newveci = veci[indvec] newvecj = vecj[indvec] if vecj[indvec+1] == vecj[indvec]: faces = np.array(['N']) else: faces = np.array(['W']) indvec += 1 while indvec+1 < len(veci): if veci[indvec] == veci[indvec-1]: if vecj[indvec] > vecj[indvec-1]: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) faces = np.append(faces, np.array(['W'])) if veci[indvec+1] > veci[indvec]: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) faces = np.append(faces, np.array(['N'])) else: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) if veci[indvec+1] > veci[indvec]: faces = np.append(faces, np.array(['N'])) else: faces = np.append(faces, np.array(['W'])) else: if veci[indvec+1] == veci[indvec]: if vecj[indvec+1] < vecj[indvec]: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) faces = np.append(faces, np.array('W')) else: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) faces = np.append(faces, np.array('N')) indvec = indvec+1 # when indvec==length(veci) # note that new sequence ends with N if veci[indvec] == veci[indvec-1]: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) if vecj[indvec] > vecj[indvec-1]: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) faces = np.append(faces, np.array(['W', 'N'])) else: faces = np.append(faces, 'N') else: newveci = np.append(newveci, veci[indvec]) newvecj = np.append(newvecj, vecj[indvec]) faces = np.append(faces, 'N') if changedir: newveci = newveci[::-1] newvecj = newvecj[::-1] faces = faces[::-1] orientation = make_orientation(newveci, faces, dire) return faces, newveci, newvecj, orientation
[docs]def make_orientation(newveci, faces, dire): """ Function that allows to extract the orientation of the faces, depending on which face and on the orientation of the segment :param numpy.array newveci: array that contains the section indices (used only for recovering the size of output) :param numpy.array faces: array that contains the faces of the section cells :param str dire: a string that contains the orientation of the segment """ orientation = np.zeros(len(newveci)) for l in xrange(0, len(newveci)): if faces[l] == 'W': if dire[1] == 'W': orientation[l] = -1 else: orientation[l] = 1 if faces[l] == 'N': if dire[0] == 'N': orientation[l] = 1 else: orientation[l] = -1 return orientation
[docs]def monotonous(vect): """ Determines whether the input array is monotonous :param numpy.array vect: Input array :return: A boolean (True or False) :rtype: bool :raises IndexError: if length of vect is 1 >>> # monotonous >>> vect = np.array([1, 2, 3]) >>> monotonous(vect) True >>> # constant >>> vect = np.array([0, 0, 0]) >>> monotonous(vect) True .. todo:: following fail >>> # bad input - only 1 item >>> vect = np.array([1]) >>> monotonous(vect) Traceback (most recent call last): ... raise IndexError """ if len(vect) == 1: logger.error('only one point in sequence; no face should be used') raise IndexError diff = vect[1:] - vect[0:-1] res = (np.all(diff >= 0)) or (np.all(diff <= 0)) return res
# Run main, if called from the command line if __name__ == '__main__': exit()