def rotated_hydro(hydro): """ hydro: xarray Dataset with a grid and edge-centered fluxes in Q. returns a new Dataset with the dual grid, 90deg rotated edge velocities, and cell-centered vector velocities. """ g = unstructured_grid.UnstructuredGrid.from_ugrid(hydro) # using centroids yields edges that aren't orthogonal, but the centers # are nicely centered in the cells. # As long as the grid is nice and orthogonal, it should be okay # use true circumcenters. gd = g.create_dual(center='circumcenter', create_cells=True, remove_1d=True) # Need to get the rotated Q en = g.edges_normals() # edge normals that go with Q on the original grid enr = utils.rot(np.pi / 2, en) dual_en = gd.edges_normals() j_orig = gd.edges['dual_edge'] edge_sign_to_dual = np.round((enr[j_orig] * dual_en).sum(axis=1)) Qdual = hydro.Q.values[j_orig] * edge_sign_to_dual Urot_dual = U_perot(gd, Qdual, gd.cells_area()) ds = gd.write_to_xarray() ds['Q'] = ('edge', ), Qdual ds['u'] = ('face', 'xy'), Urot_dual return ds
def steady_streamline_across(x0, hydro): Uc = hydro['U'] gtri = hydro['g'] Ucrot = utils.rot(np.pi / 2, Uc) left, l_cells = steady_streamline_oneway(gtri, Ucrot, x0) right, r_cells = steady_streamline_oneway(gtri, -Ucrot, x0) return np.concatenate((left[::-1], right[1:]))
def __init__(self, g, U, source_ds, alongs=None, acrosses=None, g_rot=None, U_rot=None): self.g = g self.U = U self.source_ds = source_ds self.g_rot = g_rot or self.g if U_rot is None: assert self.g == self.g_rot U_rot = utils.rot(np.pi / 2, self.U) self.U_rot = U_rot if alongs: self.alongs = alongs else: self.calc_alongs() if acrosses: self.acrosses = acrosses else: self.calc_acrosses()
def data_to_hyperbola(data,a=0,b=1): s=np.linspace(-5,5,100) # Draw hyperbolas from data: pa=np.r_[ data['rx_x'][a], data['rx_y'][a] ] pb=np.r_[ data['rx_x'][b], data['rx_y'][b] ] f0=0.5*(pa+pb) dab=pb-pa theta=np.arctan2(dab[1],dab[0]) # for the rotation focus_dist=utils.dist(dab) delta_ab=(data['rx_t'][b] - data['rx_t'][a])*0.5*(data['rx_c'][a]+data['rx_c'][b]) # well, I can get the eccentricity, right? hyp_c=0.5*utils.dist(pa-pb) # center to one focus # distance from a point to other focus # distance to this focus # (c+a) - (c-a) = delta_ab hyp_a=-delta_ab/2 ecc=hyp_c/hyp_a # ecc = sqrt(1+b^2/a^2) # ecc^2-1 = b^2/a^2 # take a^2=1 # b^2=ecc^2-1 # b=sqrt( ecc^2-1) B=np.sqrt(ecc**2-1) hxy_sim=np.c_[np.cosh(s), B*np.sinh(s)] if 0: hxy_sim_ref=np.c_[-np.cosh(s), B*np.sinh(s)] # while working through this, include the reflection hxy_sim=np.concatenate( [hxy_sim, [[np.nan,np.nan]], hxy_sim_ref]) # so a point on the hyperbola is at [1,0] # and then the focus is at [ecc,0] f1=np.array([ecc,0]) f2=-f1 deltas=utils.dist( hxy_sim-f1) - utils.dist(hxy_sim-f2) # scale it - focus is current at ecc, and I want it at # hyp_c # hyp_c/ ecc =hyp_a hxy_cong=hxy_sim * hyp_a hxy_final=utils.rot(theta,hxy_cong) + f0 + data['xy0'] return hxy_final
def __init__(self, g, U, source_ds, alongs=None, acrosses=None, bidir=False, g_rot=None, U_rot=None, along_args={}, across_args={}): self.g = g prepare_grid(g) self.U = U self.source_ds = source_ds self.g_rot = g_rot or self.g if self.g_rot != self.g: prepare_grid(self.g_rot) if U_rot is None: assert self.g == self.g_rot U_rot = utils.rot(np.pi / 2, self.U) self.U_rot = U_rot self.bidir = bidir self.along_args = dict(bidir=bidir, max_t=20 * 3600, max_dist=500) self.along_args.update(along_args) self.across_args = dict(bidir=bidir, max_t=20 * 3600, max_dist=100) self.across_args.update(across_args) if alongs: self.alongs = alongs else: self.calc_alongs() if acrosses: self.acrosses = acrosses else: self.calc_acrosses()
def steady_streamline_across(x0, hydro): Uc = hydro['U'] g = hydro['g'] Ucrot = utils.rot(np.pi / 2, Uc) return steady_streamline_twoways(x0, g, Ucrot)
x0 = source_ds.x.values[s, :] along = steady_streamline_along(x0, tri_hydro) across = steady_streamline_across(x0, tri_hydro) alongs.append(along) acrosses.append(across) ## bad = 546 x0 = source_ds.x.values[546, :] Uc = tri_hydro['U'] gtri = tri_hydro['g'] Ucrot = utils.rot(np.pi / 2, Uc) #left,l_cells=steady_streamline_oneway(gtri,Ucrot,x0) right, r_cells = steady_streamline_oneway(gtri, -Ucrot, x0) #across=steady_streamline_across(x0,tri_hydro) plt.figure(1).clf() fig, ax = plt.subplots(1, 1, num=1) gtri.plot_edges(ax=ax, color='k', lw=0.3) slc = slice(bad, bad + 1) #ax.add_collection(collections.LineCollection(alongs[slc],color='b')) #ax.add_collection(collections.LineCollection(acrosses[slc],color='g')) ax.plot(source_ds.x.values[slc, 0], source_ds.x.values[slc, 1], 'mo') ax.plot(right[:, 0], right[:, 1], 'r-o')
p_ints=[ ll2utm(np.array(r)) for r in geom.interiors] p_geoms.append( geometry.Polygon(p_ext,p_ints)) ## g_cart=unstructured_grid.UnstructuredGrid() L=290e3 W=160e3 dx=dy=2.0e3 g_cart.add_rectilinear([-W,-L/2],[0,L/2], int(1+W/dx),int(1+L/dy)) # Rotate CCW and translate 0,0 of that grid to hit ~GG g_cart.nodes['x']=utils.rot( 30*np.pi/180., g_cart.nodes['x']) + np.array([560e3,4191e3]) cart_poly=g_cart.boundary_polygon() ## # Clear out a buffer region sfb_dx_min=200 cart_dx_typ=dx # This ends up being a bit overkill, since it buffers # from parts of the bay grid which are not touching # the ocean grid. Still, the effect is kind of # nice, giving some higher near-shore resolution, so # don't fix it at this point. buff_size=(cart_dx_typ - sfb_dx_min)*10
# interpolate model to observation times mubar_i = np.interp(dtimes, mtimes, mubar[:,llind],left=np.nan,right=np.nan) mvbar_i = np.interp(dtimes, mtimes, mvbar[:,llind],left=np.nan,right=np.nan) # rotating model and obs to principle axis try: # Get NOAA reported flood direction flood_dir=float(dat['flood_dir'][:]) # convert to "math" convention, and radians flood_dir=(90-flood_dir)*np.pi/180. except Exception: print("Failed to get flood dir?!") flood_dir=0.0 # east mvec=np.asarray([mubar_i, mvbar_i]).T mtheta=principal_theta(mvec,positive=flood_dir) muvbar = rot(-mtheta,mvec).T vec=np.asarray([ubar, vbar]).T # specifying positive=mtheta is supposed to help resolve # 180 degree ambiguity theta=principal_theta(vec,positive=mtheta) uvbar = rot(-theta,vec).T obs_color='green' mod_color='lightslategray' if 1: # plotting up model & observation time series fig, ax = plt.subplots(nrows=2, sharex=True, figsize=(8,7)) if not rotate_series: ax[0].plot(mdtime[:], mubar[:,llind], color=mod_color, label='Model') ax[0].plot(dtime[:], ubar[:], '--', color=obs_color, label='ADCP')
centerline=np.concatenate([sec0,sec1,sec2]) from stompy.spatial import linestring_utils centerline=linestring_utils.resample_linearring(centerline,dx_lon,closed_ring=0) def profile(x,s): return np.linspace(-W/2.,W/2.,int(W/dy_lat)) ret=g.add_rectilinear_on_line(centerline,profile) y=g.cells['d_lat']/(W/2.0) bathy=depth_center+(y**2)*(depth_edge-depth_center) g.add_cell_field('depth',bathy,on_exists='overwrite') if rotate!=0.0: g.nodes['x']=utils.rot(rotate*np.pi/180., g.nodes['x'] ) inflow= g.nodes['x'][ret['nodes'][0,:]] outflow=g.nodes['x'][ret['nodes'][-1,:]] if 1: plt.figure(1).clf() plt.plot(centerline[:,0], centerline[:,1],'g-') g.plot_edges(color='k',lw=0.5) ccoll=g.plot_cells(values=g.cells['depth'],cmap='jet') plt.colorbar(ccoll) plt.axis('equal')
adcp = xr.open_dataset('/home/rusty/data/noaa/ports/SFB1304-2013.nc') ## U = np.array([adcp.u_davg, adcp.v_davg]).T ## theta = utils.principal_theta(U) print "Rotating to positive is %d compass" % ((90 - (theta * 180 / np.pi)) % 360) # theta gives the direction of flood-positive currents. To get that # component into the 'x' component, rotate by -theta Urot = utils.rot(-theta, U) ## fig = plt.figure(2) fig.clf() fig.set_size_inches([14, 8], forward=True) fig, (ax_spring, ax_neap) = plt.subplots(2, 1, sharey=True, num=2) for ax in [ax_spring, ax_neap]: ax.plot(adcp.time, Urot[:, 0], label='Depth avg vel.') ax.set_ylabel('m/s floodward') ax.grid(1) # starts with ebb, ends with flood
alongs = [] for i in utils.progress(range(len(cutoff_xyz))): x0 = cutoff_xyz[i, :2] along = stream_tracer.steady_streamline_twoways(g_sub, unit_flux_vec, x0, max_t=20 * 3600, bidir=False, max_dist=500.) alongs.append(along) ## acrosses = [] unit_flux_vec_rot = utils.rot(np.pi / 2, unit_flux_vec) for i in utils.progress(range(len(cutoff_xyz))): x0 = cutoff_xyz[i, :2] across = stream_tracer.steady_streamline_twoways(g_sub, unit_flux_vec_rot, x0, max_t=20 * 3600, bidir=False, max_dist=100.) acrosses.append(across) ## a_segs = [a.x.values for a in alongs] acoll = collections.LineCollection(a_segs, color='r', lw=0.5, alpha=0.5)
def summary_figure(self, num=3): fig = plt.figure(num) fig.clf() ax_map = fig.add_subplot(1, 2, 1) ax_V = fig.add_subplot(1, 2, 2) xyxy = self.region_poly.bounds clip = [xyxy[0], xyxy[2], xyxy[1], xyxy[3]] hyp = self.hyp # hyp.g.plot_edges(clip=clip,ax=ax_map,color='k',lw=0.4,alpha=0.4) plot_wkb.plot_wkb(hyp.g_poly, fc='0.8', ec='none', ax=ax_map, zorder=-4) hyp.g.plot_cells(mask=self.region_cells, ax=ax_map, color='orange') # Show the location of the reference station ax_map.plot([ self.hyp.his.station_x_coordinate.isel( stations=self.region_station) ], [ self.hyp.his.station_y_coordinate.isel( stations=self.region_station) ], 'go') # bound_xs=self.bounding_cross_sections() xys = [] uvs = [] for k in self.bound_xs.keys(): sgn = self.bound_xs[k] sec_x = self.hyp.his.cross_section_x_coordinate.isel( cross_section=k).values sec_y = self.hyp.his.cross_section_y_coordinate.isel( cross_section=k).values sec_xy = np.c_[sec_x, sec_y] sec_xy = sec_xy[sec_xy[:, 0] < 1e10] ax_map.plot(sec_xy[:, 0], sec_xy[:, 1], 'r-') uvs.append(sgn * (sec_xy[-1] - sec_xy[0])) xys.append(sec_xy.mean(axis=0)) xys = np.array(xys) uvs = np.array(uvs) uvs = utils.rot(-np.pi / 2, utils.to_unit(uvs)) ax_map.quiver(xys[:, 0], xys[:, 1], uvs[:, 0], uvs[:, 1]) ax_map.axis('equal') order = np.argsort(self.eta) ax_V.plot(self.eta[order], self.vol_and_Q[order], label="model") ax_V.plot(self.dem_etas, self.dem_volumes, label='DEM', color='k', lw=0.6) # and what we expect from the model, assuming nonlin2d=0 cell_etas, cell_vols = self.calculate_cell_volumes() ax_V.plot(cell_etas, cell_vols, label='Cell depth', color='r', lw=0.6) ax_V.set_ylabel('Vol') ax_V.set_xlabel('eta') ax_V.legend() return fig
'g-', lw=1.5) ## def ll_to_lonilati(ll, coastal_ds): """ Match lon/lat coordinates to a cell in the coastal_ds dataset. ll: [lon,lat] coastal_ds: xarray dataset, assumed to be lon/lat grid, rectilinear. """ loni = utils.nearest(snap_lon % 360, g_map_ll[c, 0] % 360) lati = utils.nearest(snap_lat, g_map_ll[c, 1]) err_km = utils.haversine([snap_lon[loni], snap_lat[lati]], g_map_ll[c, :]) # HERE - instead of reinventing here, generalize the ROMS # code. even if that means repeated BC sources. # match contiguous runs of nodes/edges with sources # of hycom/roms cells probes = [] for na, nb in zip(boundary_nodes[:-1], boundary_nodes[1:]): jab = g.nodes_to_edge([na, nb]) vec_AB = utils.rot(-np.pi / 2, g_ll.nodes['x'][nb] - g_ll.nodes['x'][na]) probe_xy = g_ll.nodes['x'][[na, nb]].mean(axis=0) + 0.5 * vec_AB probes.append(probe_xy)