def test_2():

    # source grid
    sgrid = mint.Grid()
    # lat-lon
    sgrid.setFlags(1, 1)
    sgrid.loadFromUgrid2DFile(f'{DATA_DIR}/cs_4.nc$physics') #lfric_diag_wind.nc$Mesh2d')

    # destination grid
    dgrid = mint.Grid()
    # cubed-sphere
    dgrid.setFlags(1, 1) #0, 0)
    dgrid.loadFromUgrid2DFile(f'{DATA_DIR}/cs_4.nc$physics') #latlon100x50.nc$latlon')

    regridder = mint.RegridEdges()
    regridder.setSrcGrid(sgrid)
    regridder.setDstGrid(dgrid)
    regridder.buildLocator(numCellsPerBucket=128, periodX=360.0, enableFolding=False)
    regridder.computeWeights(debug=2)

    # get the cell-by-cell points
    spoints = sgrid.getPoints()

    # create src data
    numSrcCells = sgrid.getNumberOfCells()
    sdata = numpy.zeros((numSrcCells, 4), numpy.float64)

    # allocate dst data array
    numDstCells = dgrid.getNumberOfCells()
    ddata = numpy.zeros((numDstCells, 4), numpy.float64)

    # centre of the vortex
    xVortexCentre, yVortexCentre = 10.0, 20.0

    for icell in range(numSrcCells):
        for i0 in range(4):
            # i1 is the second point of the edge in
            # anticlockwise direction
            i1 = (i0 + 1) % 4
            x0, y0 = spoints[icell, i0, :2]
            x1, y1 = spoints[icell, i1, :2]
            # our convention is to have the edges pointing in the
            # positive parametric direction, the last two edges
            # have the wrong sign
            sign = 1 - 2*(i0 // 2)
            # associate the same vorticity to each edge
            potential0 = math.atan2(y0 - yVortexCentre, x0 - xVortexCentre) / TWOPI
            potential1 = math.atan2(y1 - yVortexCentre, x1 - yVortexCentre) / TWOPI
            dPotential = potential1 - potential0
            if dPotential > 0.5:
                print(f'd potential = {dPotential}, will -= 1... icell={icell} edge={i0} p0={x0:.3f},{y0:.3f} p1={x1:.3f},{y1:.3f}')
                dPotential -= 1.
            elif dPotential < -0.5:
                print(f'd potential = {dPotential}, will += 1... icell={icell} edge={i0} p0={x0:.3f},{y0:.3f} p1={x1:.3f},{y1:.3f}')
                dPotential += 1.0
            sdata[icell, i0] = sign * dPotential

    # apply the weights
    regridder.apply(sdata, ddata, placement=mint.CELL_BY_CELL_DATA)

    xContourCentre, yContourCentre = xVortexCentre, yVortexCentre
    contourRadius = 4.0
    numContourPoints = 8
    dTheta = TWOPI / float(numContourPoints)

    # compute the flow across a broken line
    xyz = numpy.array([(xContourCentre + contourRadius*math.cos(i*dTheta),
                        yContourCentre + contourRadius*math.sin(i*dTheta), 
                        0.0) for i in range(0, numContourPoints + 1)])
    print(xyz)

    sflux = mint.PolylineIntegral()
    sflux.setGrid(sgrid)
    sflux.buildLocator(numCellsPerBucket=128, periodX=0.) #360.0, enableFolding=False)
    sflux.computeWeights(xyz)

    dflux = mint.PolylineIntegral()
    dflux.setGrid(dgrid)
    dflux.buildLocator(numCellsPerBucket=128, periodX=0.) #360.0, enableFolding=False)
    dflux.computeWeights(xyz)

    srcFluxVal = sflux.getIntegral(sdata)
    dstFluxVal = dflux.getIntegral(ddata)
    print(f'flux: src: {srcFluxVal} dst: {dstFluxVal}')

    # save the grids and fields to VTK files
    sgrid.dump('sgrid.vtk')
    dgrid.dump('dgrid.vtk')

    # mint.printLogMessages()
    mint.writeLogMessages('test_regrid_edges_latlon2cubedsphere.log')
def test_1():

    # source grid
    sgrid = mint.Grid()
    # lat-lon
    sgrid.setFlags(0, 0)
    sgrid.loadFromUgrid2DFile(f'{DATA_DIR}/latlon100x50.nc$latlon')

    # destination grid
    dgrid = mint.Grid()
    # cubed-sphere
    dgrid.setFlags(1, 1)
    dgrid.loadFromUgrid2DFile(f'{DATA_DIR}/lfric_diag_wind.nc$Mesh2d')

    regridder = mint.RegridEdges()
    regridder.setSrcGrid(sgrid)
    regridder.setDstGrid(dgrid)
    regridder.buildLocator(numCellsPerBucket=128, periodX=360.0, enableFolding=False)
    regridder.computeWeights(debug=2)

    # get the cell-by-cell points
    spoints = sgrid.getPoints()

    # create src data
    numSrcCells = sgrid.getNumberOfCells()
    sdata = numpy.zeros((numSrcCells, 4), numpy.float64)

    # allocate dst data array
    numDstCells = dgrid.getNumberOfCells()
    ddata = numpy.zeros((numDstCells, 4), numpy.float64)

    for icell in range(numSrcCells):
        for i0 in range(4):
            # i1 is the second point of the edge in
            # anticlockwise direction
            i1 = (i0 + 1) % 4
            p0 = spoints[icell, i0, :]
            p1 = spoints[icell, i1, :]
            # our convention is to have the edges pointing in the
            # positive parametric direction, the last two edges
            # have the wrong sign
            sign = 1 - 2*(i0 // 2)
            # associate the same vorticity to each edge
            sdata[icell, i0] = sign * (streamFunc(p1) - streamFunc(p0))

    # apply the weights
    regridder.apply(sdata, ddata, placement=mint.CELL_BY_CELL_DATA)

    # compute the flow across a broken line
    xyz = numpy.array([(-170., -80., 0.), (170., 80., 0.)])

    sflux = mint.PolylineIntegral()
    sflux.setGrid(sgrid)
    sflux.buildLocator(numCellsPerBucket=128, periodX=360.0, enableFolding=False)
    sflux.computeWeights(xyz)

    dflux = mint.PolylineIntegral()
    dflux.setGrid(dgrid)
    dflux.buildLocator(numCellsPerBucket=128, periodX=360.0, enableFolding=False)
    dflux.computeWeights(xyz)

    exactFlux = streamFunc(xyz[-1, :]) - streamFunc(xyz[0, :])
    srcFluxVal = sflux.getIntegral(sdata)
    errSrcFlux = srcFluxVal - exactFlux
    dstFluxVal = dflux.getIntegral(ddata)
    errDstFlux = dstFluxVal - exactFlux
    print(f'fluxes: exact={exactFlux} over grid src: {srcFluxVal} (error={errSrcFlux:.2g}) dst: {dstFluxVal} (error={errDstFlux:.2g})')

    # save the grids and fields to VTK files
    sgrid.dump('sgrid.vtk')
    dgrid.dump('dgrid.vtk')

    mint.printLogMessages()
    mint.writeLogMessages('test_regrid_edges_latlon2cubedsphere.log')
예제 #3
0
    def __init__(self):

        self.xymin = (-180., -90.)
        self.xymax = (+180., +90.)

        # create grid
        self.grid = mint.Grid()
        # cubed-sphere
        self.grid.setFlags(1, 1, degrees=True)
        self.grid.loadFromUgrid2DFile(f'{DATA_DIR}/lfric_diag_wind.nc$Mesh2d')
        self.points = self.grid.getPoints()

        ncells = self.grid.getNumberOfCells()

        self.data = numpy.zeros((ncells, mint.NUM_EDGES_PER_QUAD))
        self.xymin = numpy.array([float('inf'), float('inf')])
        self.xymax = numpy.array([-float('inf'), -float('inf')])

        for k in range(ncells):

            # node indexing
            #  3-->--2
            #  |     |
            #  ^     ^
            #  |     |
            #  0-->--1

            # edge indexing
            #     2
            #  +-->--+
            #  |     |
            # 3^     ^1
            #  |     |
            #  +-->--+
            #     0

            for i0 in range(mint.NUM_VERTS_PER_QUAD):

                i1 = (i0 + 1) % mint.NUM_VERTS_PER_QUAD

                p0 = self.points[k, i0, :]
                p1 = self.points[k, i1, :]

                self.xymin[0] = min(self.xymin[0], p0[0])
                self.xymin[1] = min(self.xymin[1], p0[1])

                self.xymax[0] = max(self.xymax[0], p0[0])
                self.xymax[1] = max(self.xymax[1], p0[1])

                s0 = streamFunction(p0)
                s1 = streamFunction(p1)

                sign = 1 - 2 * (i0 // 2)

                ds = sign * (s1 - s0)

                # take into account the multivaluedness
                if ds > 0.5:
                    ds -= 1.0
                elif ds < -0.5:
                    ds += 1.0

                self.data[k, i0] = ds

        self.grid.dump('grid.vtk')
        self.saveVectorField()
예제 #4
0
    def __init__(self, infile, inmesh, pts, ndays, tindex, level):

        self.ndays = ndays
        self.nt = ndays + 1
        print(f'num times = {self.nt}')
        self.pts0 = pts

        self.numPoints = self.pts0.shape[0]

        # read the data
        self.srcGrid = mint.Grid()

        # cubed-sphere flags
        self.srcGrid.setFlags(fixLonAcrossDateline=1, averageLonAtPole=1)
        self.srcGrid.loadFromUgrid2D(infile + '$' + inmesh)


        # create a vector field interpolator
        self.vi = mint.VectorInterp()
        self.vi.setGrid(self.srcGrid)
        self.vi.buildLocator(numCellsPerBucket=200, periodX=360., enableFolding=False)

        # read the u, v components for each unique edge, in m/s
        nc = netCDF4.Dataset(infile)
        u1 = nc.variables['u1'][tindex, level, :]
        u2 = nc.variables['u2'][tindex, level, :]

        # read the coordinates
        xname, yname = nc.variables[inmesh].node_coordinates.split(' ')
        lon = nc.variables[xname][:]
        lat = nc.variables[yname][:]

        self.influxes = numpy.zeros((self.srcGrid.getNumberOfCells(), 4), numpy.float64)

        numCells = self.srcGrid.getNumberOfCells()

        pcellPoints = numpy.zeros((numCells, 3,), numpy.float64)

        self.velocities = numpy.zeros((numCells, 3), numpy.float64)

        # iterate
        for icell in range(numCells):

            pmid = numpy.zeros((3,), numpy.float64)

            for ie in range(4):

                edgeIndex, edgeSign = self.srcGrid.getEdgeId(icell, ie)
                n0, n1 = self.srcGrid.getNodeIds(icell, ie)

                lon0, lat0 = lon[n0], lat[n0]
                lon1, lat1 = lon[n1], lat[n1]

                latmid_rad = 0.5*(lat0 + lat1) * DEG2RAD
                dlon, dlat = lon1 - lon0, lat1 - lat0

                # convert velocities in m/s to deg/day
                u_deg = 3600 * 24 * u1[edgeIndex] / (DEG2RAD * A_EARTH * numpy.cos(latmid_rad))
                v_deg = 3600 * 24 * u2[edgeIndex] / (DEG2RAD * A_EARTH)

                # fluxes in deg^2/day (finite difference approximation)
                self.influxes[icell, ie] = u_deg*dlat - v_deg*dlon
                # print(f'cell {icell} edge {ie} edgeSign={edgeSign} u1,u2 = {u1[edgeIndex]},{u2[edgeIndex]} (m/s) p0={lon0},{lat0} p1={lon1},{lat1} dlon,dlat={dlon},{dlat} (deg) flux = {self.influxes[icell, ie]} (deg^2/day)')

                pmid += numpy.array((lon0, lat0, 0.))

            pmid /= 4
            pcellPoints[icell, :] = pmid

        ier = self.vi.findPoints(pcellPoints)
        assert(ier == 0)
        self.velocities = self.vi.getFaceVectors(self.influxes, placement=0)

        self.srcGrid.attach('velocity', self.velocities)
        self.srcGrid.dump('lfriz_grid.vtk')
예제 #5
0
    def compute(self):

        results = {
            'A': {'xyz': createCircle(xycenter=(XCENTRE, YCENTRE), nt=8, radius=1.0),
                          'flux': float('nan'),
                          'exact': 1.0,
                         },
            'B': {'xyz': createCircle(xycenter=(0., 0.), nt=32, radius=70.0),
                           'flux': float('nan'),
                           'exact': 1.0,
                         },
            'C': {'xyz': createCircle(xycenter=(-80., -30.), nt=16, radius=30.),
                           'flux': float('nan'),
                           'exact': 0.0,
                         },
            'D': {'xyz': createLoop(xybeg=(180., +45.),
                                    xyend=(180., -45.0), nt=15),
                           'flux': float('nan'),
                           'exact': streamFunction((180., -45.)) - \
                                    streamFunction((180., +45.)) + 1.,
                         },
            'E': {'xyz': createLoop(xybeg=(162.5, +52.0),
                                    xyend=(162.5, -52.0), nt=15),
                           'flux': float('nan'),
                           'exact': streamFunction((162.5, -52.0)) - \
                                    streamFunction((162.5, +52.0)) + 1.,
                         },
        }

        targetData = []
        targetGrids = []
        resolutions = ('40x20', '80x40', '160x80')
        for res in resolutions:

            grid2 = mint.Grid()
            grid2.setFlags(0, 0, degrees=True)  # uniform
            grid2.loadFromUgrid2DFile(f'{DATA_DIR}/latlon{res}Shifted.nc$mesh')
            grid2.dump(f'lonlat{res}.vtk')

            regridder = mint.RegridEdges()
            regridder.setSrcGrid(self.grid)
            regridder.setDstGrid(grid2)
            regridder.buildLocator(numCellsPerBucket=100,
                                   periodX=0.0,
                                   enableFolding=0)
            regridder.computeWeights(debug=2)

            ncells2 = grid2.getNumberOfCells()
            data2 = numpy.zeros((ncells2, mint.NUM_EDGES_PER_QUAD),
                                numpy.float64)
            regridder.apply(self.data, data2, placement=mint.CELL_BY_CELL_DATA)

            targetData.append(data2)
            targetGrids.append(grid2)

        for case in results:

            errors = []

            pli = mint.PolylineIntegral()
            pli.setGrid(self.grid)
            # no periodicity in x
            pli.buildLocator(numCellsPerBucket=128,
                             periodX=0,
                             enableFolding=False)
            pli.computeWeights(results[case]['xyz'])
            flux = pli.getIntegral(self.data)

            # save the contour in VTK file
            saveLineVTK(results[case]['xyz'], case + '.vtk')

            error = flux - results[case]["exact"]
            print(f'{case} errors cs: {error:.2g}', end='')

            for ires in range(len(targetGrids)):

                pli = mint.PolylineIntegral()

                grid2 = targetGrids[ires]
                data2 = targetData[ires]

                pli.setGrid(grid2)
                # no periodicity in x
                pli.buildLocator(numCellsPerBucket=128,
                                 periodX=0,
                                 enableFolding=False)
                pli.computeWeights(results[case]['xyz'])
                flux2 = pli.getIntegral(data2)

                error = flux2 - results[case]["exact"]
                print(f' {resolutions[ires]}: {error:.2g}', end='')
            print('')