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')
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()
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')
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('')