def process_quad_patch(name, M=None): center_idx = np.nonzero(centerlines['name'] == name)[0][0] centerline = centerlines['geom'][center_idx] if M is None: M = centerlines['rows'][center_idx] bound = bounds['geom'][bounds['name'] == name][0] center = linestring_utils.resample_linearring(np.array(centerline), scale, closed_ring=0) g = unstructured_grid.UnstructuredGrid(max_sides=6) # Smooth the exterior ext_points = np.array(bound.exterior) ext_points = linestring_utils.resample_linearring(ext_points, scale, closed_ring=True) from stompy import filters ext_points[:, 0] = filters.lowpass_fir(ext_points[:, 0], 3) ext_points[:, 1] = filters.lowpass_fir(ext_points[:, 1], 3) smooth_bound = geometry.Polygon(ext_points) L = smooth_bound.exterior.length def profile(x, s, perp): probe_left = geometry.LineString([x, x + L * perp]) probe_right = geometry.LineString([x, x - L * perp]) left_cross = smooth_bound.exterior.intersection(probe_left) right_cross = smooth_bound.exterior.intersection(probe_right) assert left_cross.type == 'Point', "Fix this for multiple intersections" assert right_cross.type == 'Point', "Fix this for multiple intersections" pnt_left = np.array(left_cross) pnt_right = np.array(right_cross) d_left = utils.dist(x, pnt_left) d_right = utils.dist(x, pnt_right) return np.interp(np.linspace(-1, 1, M), [-1, 0, 1], [-d_right, 0, d_left]) g.add_rectilinear_on_line(center, profile) g.renumber() return g
def test_embedded_channel(): assert False # no API yet. # trying out degenerate internal lines - the trick may be mostly in # how to specify them. # make a large rectangle, with a sinuous channel in the middle L = 500.0 W = 300.0 rect = np.array([[0, 0], [L, 0], [L, W], [0, W]]) x = np.linspace(0.1 * L, 0.9 * L, 50) y = W / 2 + 0.1 * W * np.cos(4 * np.pi * x / L) shore = np.swapaxes(np.concatenate((x[None, :], y[None, :])), 0, 1) density = field.ConstantField(10) # this will probably get moved into Paver itself. # Note closed_ring=0 ! shore = resample_linearring(shore, density, closed_ring=0) south_shore = shore - np.array([0, 0.1 * W]) north_shore = shore + np.array([0, 0.1 * W]) p = paver.Paving([rect], density, degenerates=[north_shore, south_shore]) p.pave_all()
def add_monitor_transects(self,features,dx=None): """ Add a sampled transect. dx=None will eventually just pull each cell along the line. otherwise sample at even distance dx. """ # Sample each cell intersecting the given feature assert dx is not None,"Not ready for adaptive transect resolution" for feat in features: pnts=np.array(feat['geom']) pnts=linestring_utils.resample_linearring(pnts,dx,closed_ring=False) self.log.info("Resampling leads to %d points for %s"%(len(pnts),feat['name'])) # punt with length of the name -- not sure if DFM is okay with >20 characters pnts_and_names=[ dict(geom=geometry.Point(pnt),name="%s_%04d"%(feat['name'][:13],i)) for i,pnt in enumerate(pnts) ] self.add_monitor_points(pnts_and_names)
def dem_analysis(self, bathy_fn): # 1.0 is from half the current DEM resolution pad = 10.0 bounds = [ self.section_ls[:, 0].min() - pad, self.section_ls[:, 0].max() + pad, self.section_ls[:, 1].min() - pad, self.section_ls[:, 1].max() + pad ] self.dem = field.GdalGrid(bathy_fn, geo_bounds=bounds) res = 0.5 * self.dem.dx self.section_segs = linestring_utils.resample_linearring( self.section_ls, res, closed_ring=0) self.section_z = self.dem(self.section_segs) self.section_s = utils.dist_along(self.section_segs)
def eval_pnt_pair(pnt_pair, node_depths): metrics = {} nodes = metrics['nodes'] = [g.select_nodes_nearest(xy) for xy in pnt_pair] node_path = metrics['node_path'] = g.shortest_path(nodes[0], nodes[1]) path_xy = metrics['path_xy'] = g.nodes['x'][node_path] path_dist = metrics['path_dist'] = utils.dist_along(path_xy) path_z = metrics['path_z'] = node_depths[node_path] resamp_xy = linestring_utils.resample_linearring(path_xy, 2.0, closed_ring=False) metrics['resamp_xy'] = resamp_xy metrics['resamp_z'] = resamp_z = dem(resamp_xy) metrics['resamp_dist'] = resamp_dist = utils.dist_along(resamp_xy) # edge depths with bedlevtyp3, sampled to higher resolution seg_z_typ3 = 0.5 * (path_z[:-1] + path_z[1:]) resamp_z_typ3 = seg_z_typ3[ np.searchsorted(path_dist, resamp_dist).clip(1, len(path_dist) - 1) - 1] metrics['resamp_z_typ3'] = resamp_z_typ3 metrics['ref_eta'] = ref_eta = 1.0 A_dem = np.trapz((ref_eta - resamp_z).clip(0, np.inf), resamp_dist) L_dem = np.trapz(1. * (ref_eta > resamp_z), resamp_dist) A_typ3 = np.trapz((ref_eta - resamp_z_typ3).clip(0, np.inf), resamp_dist) L_typ3 = np.trapz(1. * (ref_eta > resamp_z_typ3), resamp_dist) metrics['A_dem'] = A_dem metrics['L_dem'] = L_dem metrics['A_typ3'] = A_typ3 metrics['L_typ3'] = L_typ3 metrics['A_err'] = A_typ3 - A_dem metrics['L_err'] = L_typ3 - L_dem metrics['z_err'] = metrics['A_err'] / (L_dem + 0.1) return metrics
def resample_to_common(trans,dz=None,dx=None,resample_x=True,resample_z=True, seg=None,save_original='orig_'): """ trans: list of xr_transect Datasets. dx: length scale for horizontal resampling, defaults to median. Pass 0 to use seg as is. dz: length scale for vertical resampling. defaults to 10th percentile. resample_x: can be set to false to skip horizontal resampling if all transects already have the same horizontal coordinates resample_z: can be set to false to skip vertical resampling if all transects already have the same vertical coordinates. seg: the linestring of the new transect. defaults to fitting a line. save_original: if not None, a prefix for saving coordinates before resampling. """ if resample_z: trans=resample_to_common_z(trans,dz=dz,save_original=save_original) if resample_x: if seg is None: seg=transects_to_segment(trans) if dx is None: # Define the target vertical and horizontal bins all_dx=[get_dx_sample(tran).values for tran in trans] median_dx=np.median(np.concatenate(all_dx)) dx=median_dx if dx>=0: # Keep this general, so that segment is allowed to have more than # just two vertices new_xy = linestring_utils.resample_linearring(seg,dx,closed_ring=False) else: new_xy = seg trans=[resample_d(tran,new_xy,save_original=save_original) for tran in trans] return trans
hydro = extract_global(model) ## # Sample datasets if 1: import bathy dem = bathy.dem() # fake, sparser tracks. adcp_shp = wkb2shp.shp2geom('sparse_fake_bathy_trackline.shp') xys = [] for feat in adcp_shp['geom']: feat_xy = np.array(feat) feat_xy = linestring_utils.resample_linearring(feat_xy, 1.0, closed_ring=0) feat_xy = filters.lowpass_fir(feat_xy, winsize=6, axis=0) xys.append(feat_xy) adcp_xy = np.concatenate(xys) source_ds = xr.Dataset() source_ds['x'] = ('sample', 'xy'), adcp_xy source_ds['z'] = ('sample', ), dem(adcp_xy) ## def steady_streamline_oneway(g, Uc, x0, max_t=3600, max_dist=np.inf): # trace some streamlines x0 = np.asarray(x0) t0 = 0.0
# domain boundary including the random noise ring_noise = ring + noise_lp[:, None] * ring_norm # Create the curvilinear section thalweg = centerline[50:110] plt.figure(1).clf() plt.plot(centerline[:, 0], centerline[:, 1], 'k-', zorder=2) plt.axis('equal') plot_wkb.plot_wkb(channel, zorder=-2) plt.plot(ring_noise[:, 0], ring_noise[:, 1], 'm-') plt.plot(thalweg[:, 0], thalweg[:, 1], 'r--', lw=3) ## # First, just the curvilinear section: g = unstructured_grid.UnstructuredGrid(max_sides=4) thalweg_resamp = linestring_utils.resample_linearring(thalweg, 50, closed_ring=0) g.add_rectilinear_on_line( thalweg_resamp, profile=lambda x, s, perp: np.linspace(-200, 200, 20), add_streamwise=False) g.plot_edges(zorder=5, color='y')
ds_resamp=[xr_transect.resample_z(tran,new_z) for tran in trans] ## plt.figure(2).clf() fig,axs=plt.subplots(2,1,num=2,sharex=True,sharey=True) xr_transect.plot_scalar(all_ds[0],all_ds[0].Ve,ax=axs[0]) xr_transect.plot_scalar(ds_resamp[0],ds_resamp[0].Ve,ax=axs[1]) ## # Keep this general, so that segment is allowed to have more than # just two vertices new_xy = linestring_utils.resample_linearring(seg,dx) ## # resampling a single transect onto the new horizontal coordinates. # can only operate on transects which have a uniform z coordinate ds_in=ds_resamp[0] assert ds_in.z_ctr.ndim==1,"Resampling horizontal requires uniform vertical coordinate" ## new_ds=xr.Dataset() new_ds['z' # x-z of a single transect:
# A centerline: sec0=np.array([[0,W/2],[L,W/2]]) s=np.linspace(0,np.pi/2,40)[1:] # skip first point x_arc=np.cos(s) y_arc=np.sin(s) bend_r=W # radius of bend bend_ctr=sec0[-1] + np.array([0,bend_r]) sec1=bend_ctr + bend_r*np.c_[ y_arc, -x_arc] sec2=np.array( [sec1[-1], sec1[-1] +np.array([0,L] ) ] ) 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'] )
dem_in_poly = dem.polygon_mask(region_poly) pixA = dem.dx * dem.dy pix_z = dem.F[dem_in_poly] def eta_to_V(eta): return (pixA * (eta - pix_z).clip(0, np.inf)).sum() etas = np.linspace(-10, 5, 200) dem_volumes = np.array([eta_to_V(eta) for eta in etas]) ## from stompy.spatial import linestring_utils section_segs = linestring_utils.resample_linearring(section_ls, 0.5 * dem.dx, closed_ring=0) section_z = dem(section_segs) section_s = utils.dist_along(section_segs) def eta_to_xA(eta): return np.trapz((eta - section_z).clip(0, np.inf), section_s) dem_xas = np.array([eta_to_xA(eta) for eta in etas]) ## plt.figure(2).clf() fig, axs = plt.subplots(3, 2, sharex='col', sharey='row', num=2)
fig = plt.figure(1) fig.clf() ax = fig.add_subplot(1, 1, 1) csc_grid.plot_edges(ax=ax) ax.plot(cs_xy[:, 0], cs_xy[:, 1], 'g-', label='Cross section') ax.axis('equal') ax.axis(zoom) ## from stompy.spatial import linestring_utils # Pull profile from DEM along those lines: cs_line = linestring_utils.resample_linearring(cs_xy, 2.0, closed_ring=False) cs_dist = utils.dist_along(cs_line) # this cross-section includes levees -- skip outside the levees # channel_sel=(cs_dist>=106)&(cs_dist<=345) # or with the aligned cross-section: channel_sel = (cs_dist >= 61) & (cs_dist <= 299) cs_line_z = dem(cs_line) plt.figure(3).clf() fig, ax = plt.subplots(num=3) ax.plot(cs_dist, cs_line_z, 'k-') sel_z = cs_line_z[channel_sel] sel_d = cs_dist[channel_sel]