def _eval_derivs_boundary(self): import numpy as np import geometry_planar as GP # get x,y for boundary x,y = GP.coords2xy(self.coords) F_x,F_y = self.eval_gradient(x,y) # get tangent derivative ctd = np.cos(self.tangent_dirn) std = np.sin(self.tangent_dirn) F_s = ctd*F_x+std*F_y # get normal derivative F_n = -std*F_x + ctd*F_y # get stream function on boundary: # G_s = -F_n -> integrate G = np.zeros(len(x)) Nc = len(x) for n in range(1,Nc): Gs = -F_n[n] ds = self.spacings[n] G[n] = G[n-1]+Gs*ds self.tangent_deriv = F_s self.normal_deriv = F_n self.stream_func = G return
def _eval_solution_boundary(self): import geometry_planar as GP # get x,y for boundary x,y = GP.coords2xy(self.coords) # evaluate func on boundary self.func_vals_approx = self.eval_solution_fast(x,y) # calculate error self.boundary_error = GP.vector_norm(self.func_vals-self.func_vals_approx)\ /GP.vector_norm(self.func_vals) return
def _get_arctan2_constants(self): # disjoint polygons MPlist = self.disjoint_polygons Ncl = len(MPlist) isec_types = self.intersection_types # connected polygons pol_conn = self.connected_polygon const_atan2 = [] const_atan2_bdy = [] ##################################################################################################### # loop over disjoint polygons for i in range(Ncl): pol_disj = MPlist[i] int_bdy = isec_types.crossing_lines[i] Li = int_bdy.length # to see jump across int_bdy, get 2 points # - one from just inside pol_conn # - one from just inside pol_disj pic = int_bdy.centroid dsk_c = pic.buffer(1.e-4 * Li / 2.).intersection(pol_conn) dsk_d = pic.buffer(1.e-4 * Li / 2.).intersection(pol_disj) xi, yi = GP.coords2xy(pic.coords) xc, yc = GP.coords2xy(dsk_c.centroid.coords) xd, yd = GP.coords2xy(dsk_d.centroid.coords) Ac = GP.arctan2_branch(yc - y0, xc - x0, branch_dir=linedir) Ad = GP.arctan2_branch(yd - y0, xd - x0, branch_dir=linedir) Ai = GP.arctan2_branch(yi - y0, xi - x0, branch_dir=linedir) ################################################################################################## # correction inside the disjoint polygon if Ad < Ac - np.pi: const_atan2.append( 1 ) # need to add 2*pi to Ad to make it continuous across the boundary elif Ad > Ac + np.pi: const_atan2.append( -1 ) # need to add -2*pi to Ad to make it continuous across the boundary # correction on the boundary itself if Ai < Ac - np.pi: const_atan2_bdy.append( 1 ) # need to add 2*pi to Ai to make it continuous across the boundary elif Ai > Ac + np.pi: const_atan2_bdy.append( -1 ) # need to add -2*pi to Ai to make it continuous across the boundary else: const_atan2_bdy.append( 0) # arctan2_branch is continous approaching the boundary # (the jump is just after the boundary) ################################################################################################## self.corrections_internal = const_atan2 self.corrections_boundary = const_atan2_bdy # finish loop over disjoint polygons ##################################################################################################### return
pol_conn = MPlist[-1] const_atan2 = [] const_atan2_bdy = [] for i in range(Ncl): pol_disj = MPlist[i] int_bdy = isec_types.crossing_lines[i] Li = int_bdy.length # to see jump across int_bdy, get 2 points # - one from just inside pol_conn # - one from just inside pol_disj pic = int_bdy.centroid dsk_c = pic.buffer(1.e-4 * Li / 2.).intersection(pol_conn) dsk_d = pic.buffer(1.e-4 * Li / 2.).intersection(pol_disj) xi, yi = GP.coords2xy(pic.coords) xc, yc = GP.coords2xy(dsk_c.centroid.coords) xd, yd = GP.coords2xy(dsk_d.centroid.coords) Ac = GP.arctan2_branch(yc - y0, xc - x0, linedir=linedir) Ad = GP.arctan2_branch(yd - y0, xd - x0, linedir=linedir) Ai = GP.arctan2_branch(yi - y0, xi - x0, linedir=linedir) # print('**************************************************') # print('getting arctan2 constants') # print(pol_disj) # print(pol_conn) # print(pic) # print((xc,yc)) # print((xd,yd)) # print(' ')
def plot_solution(self,pobj=None,plot_boundary=True,show=True,\ cbar=True,**kwargs): import numpy as np import shapefile_utils as SFU import geometry_planar as GP from matplotlib import cm from matplotlib import pyplot as plt if pobj is None: # set a plot object if none exists fig = plt.figure() ax = fig.add_subplot(1,1,1) else: fig,ax = pobj if plot_boundary: # just plot values of F at boundary ss = self.get_arc_length()/1.e3 # km ax.plot(ss,self.func_vals_approx,'b',**kwargs) ax.plot(ss,self.func_vals,'.k',**kwargs) x2,y2 = np.array(self.coords).transpose() # coords can be reversed f2 = self.eval_solution_fast(x2,y2) ax.plot(ss,f2,'--r',**kwargs) xc = np.round(10.*self.coords[0][0]/1.e3)/10. # km (1dp) yc = np.round(10.*self.coords[0][1]/1.e3)/10. # km (1dp) ax.set_xlabel('arc length (km) from '+str((xc,yc))+' (km)') ax.set_ylabel('values of target function') else: # plot F everywhere bbox = self.shapely_polygon.bounds eps = self.resolution/2. # get a grid to plot F on: x0 = bbox[0] y0 = bbox[1] x1 = bbox[2] y1 = bbox[3] x = np.arange(x0,x1+eps,eps) y = np.arange(y0,y1+eps,eps) xp = np.arange(x0-.5*eps,x1+1.5*eps,eps)/1.e3 #km yp = np.arange(y0-.5*eps,y1+1.5*eps,eps)/1.e3 # make pcolor/contour plot nlevels = 10 vmin = self.func_vals.min() vmax = self.func_vals.max() dv = (vmax-vmin)/(nlevels) vlev = np.arange(vmin,vmax+dv,dv) # X,Y = np.meshgrid(x,y) F = self.eval_solution(X,Y) # cmap = cm.jet cmap.set_bad(color='w') Fm = np.ma.array(F,mask=np.isnan(F)) ################################################################## if 'basemap' not in str(type(ax)): # plotter is not a basemap (eg a normal axis object) PC = ax.pcolor(xp,yp,Fm,vmin=vmin,vmax=vmax,cmap=cmap,**kwargs) if cbar: fig.colorbar(PC) ax.contour(X/1.e3,Y/1.e3,F,vlev,colors='k',**kwargs) # plot polygon boundary x,y = GP.coords2xy(self.coords) ax.plot(x/1.e3,y/1.e3,'k',linewidth=2,**kwargs) # plot singularities x,y = GP.coords2xy(self.singularities) ax.plot(x/1.e3,y/1.e3,'.k',markersize=5) # axes labels ax.set_xlabel('x, km') ax.set_ylabel('y, km') else: # plotter is a basemap # NB need units in m for basemap PC = ax.pcolor(xp*1e3,yp*1e3,Fm,vmin=vmin,vmax=vmax,cmap=cmap,**kwargs) if cbar: fig.colorbar(PC) # plot outline x,y = GP.coords2xy(self.coords) ax.plot(x,y,'k',linewidth=2,**kwargs) # plot singularities x,y = GP.coords2xy(self.singularities) ax.plot(x,y,'.k',markersize=5,**kwargs) ################################################################## if show: plt.show(fig) return
def __init__(self,coords,func_vals,singularities=None): # initialise object import numpy as np import shapely.geometry as shgeom # http://toblerity.org/shapely/manual.html import geometry_planar as GP # also in py_funs import rtree.index as Rindex ####################################################### self.func_vals = np.array(func_vals) self.coords = 1*coords # no longer pointer to list from outside the function pcoords = 1*coords if (pcoords[0][0]!=pcoords[-1][0]) and (pcoords[0][1]!=pcoords[-1][1]): # not periodic # - BUT need last and first coordinate the same for shapely polygon print('not periodic') pcoords.append(pcoords[0]) ####################################################### ####################################################### # make shapely polygon # (coords now has end-point repeated, # self.coords doesn't) self.shapely_polygon = shgeom.Polygon(pcoords) ####################################################### ####################################################### # want to go round curve anti-clockwise x,y = GP.coords2xy(self.coords) area = GP.area_polygon_euclidean(x,y) self.area = abs(area) if area<0: print("Curve traversed in clockwise direction - reversing arrays' order") self.func_vals = list(self.func_vals) self.func_vals.reverse() self.func_vals = np.array(self.func_vals) # self.coords = list(self.coords) self.coords.reverse() self.coords = self.coords # make rtree index idx = Rindex.Index() for i,(xp,yp) in enumerate(self.coords): idx.insert(i,(xp,yp,xp,yp)) # a point is a rectangle of zero side-length self.coord_index = idx ####################################################### self.number_of_points = len(self.coords) # gets spacings,directions between points, and perimeter self.perimeter,self.resolution,\ self.spacings,self.tangent_dirn = GP.curve_info(self.coords) # # get points around boundary of polygon, then # expand points by an amount related to the spacings of the coords self.buffer_resolution = 16 # default buffer resolution # (number of segments used to approximate a quarter circle around a point.) # self.solve_exactly = solve_exactly # # if True: number of singularities and number of boundary points should be the same if singularities is None: get_sings = True else: get_sings = False self.singularities = singularities self.number_of_singularities = len(self.singularities) print('Number of boundary points : '+str(self.number_of_points)) print('Number of singularities : '+str(self.number_of_singularities)+'\n') while get_sings: # May need a couple of repetitions if too few singularities are found get_sings = self._get_singularities() # solve Laplace's eqn (get a_n) self._solve_laplace_eqn() # # evaluate error on boundary: print('\nCalculating error on the boundary...') self._eval_solution_boundary() print(str(self.boundary_error)+'\n') if 0: # evaluate normal derivative -> stream function on boundary: print('\nCalculating normal derivative -> stream function on the boundary...\n') self._eval_derivs_boundary() elif 1: # use analytical definition of stream function # - for log, this is arctan2 (+const) self._get_stream_func_bdy() return
if isec.geom_type == 'LineString': # 1 intersection print(isec.coords) Ni = 1 elif isec.geom_type == 'Point': Ni = -1 else: Ni = len(isec.geoms) if Ni > 0: # just use 1 pair (1st/last): c0 = isec.geoms[0].coords[0] c1 = isec.geoms[-1].coords[-1] isec = shgeom.LineString([c0, c1]) xp, yp = GP.coords2xy(rect0) plt.plot(xp, yp, 'b') xl, yl = ll.coords.xy plt.plot(xl, yl, 'k') xi, yi = isec.coords.xy plt.plot(xi, yi, '.g') if Ni > 0: if 1: print('shortest') clst = GP.line_splits_polygon(pol, isec, shortest=True) else: print('longest') clst = GP.line_splits_polygon(pol, isec, shortest=False)