def check_dist(self, dist=1.0): """ remove points in contour that are not a linear distance of at least <dist> from previous point. """ lin_dist = lambda p1, p2: sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) xycoords = self.longest_cont mask = ones(len(xycoords), dtype=bool) i = 0 while (i < len(xycoords) - 1): p1 = xycoords[i] j = i + 1 while(j < len(xycoords) and \ lin_dist(p1, xycoords[j]) < dist): mask[j] = 0 j += 1 i = j # fix end of array i = -1 while(len(xycoords) + i >= 0 and (not mask[i] or \ lin_dist(xycoords[0],xycoords[i]) < dist)): mask[i] = 0 i -= 1 # print results s = "::: removed %s points closer than %s m to one another :::"% \ (str(len(mask) - sum(mask)), dist) print_text(s, self.color) self.longest_cont = xycoords[mask]
def extend_boundary(self, r): """ Extends a 2d contour out from points in self.xycoords by a distance <r> (radius) in all directions. """ s = "::: extending boundary by %i meters :::" % r print_text(s, self.color) xycoords = self.xycoords polygons = [] for i, v in enumerate(xycoords): polygons.append(shapelyPoint(v[0], v[1]).buffer(r)) # union of our original polygon and convex hull p1 = cascaded_union(polygons) p2 = Polygon(zip(xycoords[:, 0], xycoords[:, 1])) p3 = cascaded_union([p1, p2]) xycoords_buf = array(zip(p3.exterior.xy[:][0], p3.exterior.xy[:][1])) self.plot_coords["xycoords_buf"] = xycoords_buf self.xycoords = xycoords_buf s = "::: extended contour created of length %i :::" % len( self.xycoords) print_text(s, self.color)
def intersection(self, new_contour): """ Take the geometric intersection of current coordinates with <new_contour>. Used primarily to replace the edge with something from a different (better) data set. """ contour = self.longest_cont p1 = Polygon(zip(contour[:, 0], contour[:, 1])) p2 = Polygon(zip(new_contour[:, 0], new_contour[:, 1])) intersection = p1.intersection(p2) # check if multi-polygon is created. If so, take polygon # with greatest area import collections if isinstance(intersection, collections.Iterable): p3 = max(intersection, key=lambda x: x.area) else: p3 = intersection contour_intersect = zip(p3.exterior.xy[:][0], p3.exterior.xy[:][1]) self.longest_cont = array(contour_intersect)[1:] s = "::: intersection contour created, length %s nodes :::" print_text(s % shape(self.longest_cont)[0], self.color)
def extend_edge(self, r): """ Extends a 2d contour out from points labeled in self.edge by a distance <r> (radius) in all directions. NOTE: this only works for greenland. """ s = "::: extending edge by %i meters :::" % r print_text(s, self.color) xycoords = self.xycoords edge = self.edge polygons = [] for i, v in enumerate(xycoords): if edge[i]: polygons.append(shapelyPoint(v[0], v[1]).buffer(r)) # union of our original polygon and convex hull p1 = cascaded_union(polygons) p2 = Polygon(zip(xycoords[:, 0], xycoords[:, 1])) p3 = cascaded_union([p1, p2]) xycoords_buf = array(zip(p3.exterior.xy[:][0], p3.exterior.xy[:][1])) self.plot_coords["xycoords_buf"] = xycoords_buf self.xycoords = xycoords_buf
def finish(self, field): """ figure out background field and close the .geo file. """ f = self.f fd = str(field) flist = self.fieldList # get a string of the fields list : l = "" for i, j in enumerate(flist): l += str(j) if i != len(flist) - 1: l += ', ' # make the background mesh size the minimum of the fields : if len(flist) > 0: f.write("Field[" + fd + "] = Min;\n") f.write("Field[" + fd + "].FieldsList = {" + l + "};\n") f.write("Background Field = " + fd + ";\n\n") else: f.write("Background Field = " + fd + ";\n\n") s = 'finished, closing \"' + self.direc + self.fn + '.geo\".' print_text(s, self.color) f.close()
def intersection(self, other): """ Take the geometric intersection of current coordinates with <other>. Used primarily to replace the edge with something from a different (better) data set. NOTE: it's probably better to extend the boundary before taking the intersection. """ s = "::: taking intersection with new contour of length %i :::" print_text(s % len(other), self.color) xycoords = self.xycoords p1 = Polygon(zip(xycoords[:, 0], xycoords[:, 1])) p2 = Polygon(zip(other[:, 0], other[:, 1])) intersection = p1.intersection(p2) # check if multi-polygon is created. If so, take polygon with greatest # area import collections if isinstance(intersection, collections.Iterable): p3 = max(intersection, key=lambda x: x.area) else: p3 = intersection xycoords_intersect = array(zip(p3.exterior.xy[:][0], \ p3.exterior.xy[:][1])) self.plot_coords["xycoords_intersect"] = xycoords_intersect self.xycoords = xycoords_intersect s = "::: intersection created with length %i :::" print_text(s % len(self.xycoords), self.color)
def close_file(self): """ close the .geo file down for further editing. """ s = '::: finished, closing \"' + self.direc + self.fn + '.geo\" :::' print_text(s, self.color) self.f.close()
def __init__(self, di, basin=None): """ """ self.color = 'grey_46' self.di = di s = "::: INITIALIZING BASIN GENERATOR :::" print_text(s, self.color) self.plot_coords = {} # Get path of this file, which should be in the src directory filename = inspect.getframeinfo(inspect.currentframe()).filename home = os.path.dirname(os.path.abspath(filename)) + "/.." if di.cont == "greenland": path = home + "/data/greenland/basins/" self.datafile = path + "GrnDrainageSystems_Ekholm.txt" self.imagefile = path + "Grn_Drainage_Systems.png" elif di.cont == "antarctica": path = home + "/data/antarctica/basins/" self.datafile = path + "Ant_Full_DrainageSystem_Polygons.txt" self.imagefile = path + "Ant_ICESatDSMaps_Fig_1.jpg" else: s = "Can not find data corresponding to location %s" % di.cont print_text(s, 'red', 1) if basin == None: self.show_and_get_basin() else: self.basin = basin self.retrive_basin_latlong() self.convert_to_projection()
def show_and_get_basin(self): """ """ print_text(self.imagefile, self.color) image = Image.open(self.imagefile) image.show() self.basin = raw_input("Input the numerical code of the basin.\n")
def restart(self): """ clear all contents from the .geo file. """ self.f.close self.f = open(self.direc + self.fn + '.geo', 'w') s = 'Reopened \"' + self.direc + self.fn + '.geo\".' print_text(s, self.color)
def remove_skip_points(self, skip_pts): """ remove every other <skip_pts> node from the contour. """ # remove skip points and last point to avoid overlap : longest_cont = self.longest_cont self.longest_cont = longest_cont[::skip_pts, :][:-1, :] s = "::: contour points skipped, new length %s nodes :::" print_text(s % shape(self.longest_cont)[0], self.color)
def create_2D_mesh(self, outfile): """ create the 2D mesh to file <outfile>.msh. """ #FIXME: this fails every time, the call in the terminal does work however. cmd = 'gmsh ' + '-2 ' + self.direc + self.fn + '.geo' # -2 -o ' \ #+ self.direc + outfile + '.msh' s = "\nExecuting :\n\n\t", cmd, "\n\n" print_text(s, self.color) subprocess.call(cmd.split())
def plot_contour(self): """ Plot the contour created with the "create_contour" method. """ s = "::: plotting contour :::" print_text(s, self.color) ax = self.ax lc = self.longest_cont ax.plot(lc[:, 0], lc[:, 1], 'r-', lw=3.0) ax.set_title("contour") show()
def convert_msh_to_xml(self, mshfile, xmlfile): """ convert <mshfile> .msh file to .xml file <xmlfile> via dolfin-convert. """ msh = self.direc + mshfile + '.msh' xml = self.direc + xmlfile + '.xml' cmd = 'dolfin-convert ' + msh + ' ' + xml s = "\nExecuting :\n\n\t %s\n\n" % cmd print_text(s, self.color) subprocess.call(cmd.split())
def set_contour(self, cont_array): """ This is an alternative to the create_contour method that allows you to manually specify contour points. Inputs: cont_array : A numpy array of contour points (i.e. array([[1,2],[3,4],...])) """ s = "::: manually setting contour with %s nodes:::" print_text(s % shape(cont_array)[0], self.color) fig = figure() self.ax = fig.add_subplot(111) self.ax.set_aspect('equal') self.longest_cont = cont_array
def write_gmsh_contour(self, lc=100000, boundary_extend=True): """ write the contour created with create_contour to the .geo file with mesh spacing <lc>. If <boundary_extend> is true, the spacing in the interior of the domain will be the same as the distance between nodes on the contour. """ #FIXME: sporadic results when used with ipython, does not stops writing the # file after a certain point. calling restart() then write again # results in correct .geo file written. However, running the script # outside of ipython works. s = "::: writing gmsh contour to \"%s%s.geo\" :::" print_text(s % (self.direc, self.fn), self.color) c = self.longest_cont f = self.f pts = size(c[:, 0]) # write the file to .geo file : f.write("// Mesh spacing\n") f.write("lc = " + str(lc) + ";\n\n") f.write("// Points\n") for i in range(pts): f.write("Point(" + str(i) + ") = {" + str(c[i,0]) + "," \ + str(c[i,1]) + ",0,lc};\n") f.write("\n// Lines\n") for i in range(pts - 1): f.write("Line(" + str(i) + ") = {" + str(i) + "," + str(i + 1) + "};\n") f.write("Line(" + str(pts-1) + ") = {" + str(pts-1) + "," \ + str(0) + "};\n\n") f.write("// Line loop\n") loop = "" loop += "{" for i in range(pts - 1): loop += str(i) + "," loop += str(pts - 1) + "}" f.write("Line Loop(" + str(pts + 1) + ") = " + loop + ";\n\n") f.write("// Surface\n") surf_num = pts + 2 f.write("Plane Surface(" + str(surf_num) + ") = {" + str(pts + 1) + "};\n\n") if not boundary_extend: f.write("Mesh.CharacteristicLengthExtendFromBoundary = 0;\n\n") self.surf_num = surf_num self.pts = pts self.loop = loop
def extrude(self, h, n_layers): """ Extrude the mesh <h> units with <n_layers> number of layers. """ s = "::: extruding gmsh contour %i layers :::" % n_layers print_text(s, self.color) f = self.f s = str(self.surf_num) h = str(h) layers = str(n_layers) f.write("Extrude {0,0," + h + "}" \ + "{Surface{" + s + "};" \ + "Layers{" + layers + "};}\n\n")
def transform_contour(self, di): """ Transforms the coordinates of the contour to DataInput object <di>'s projection coordinates. """ if type(di) == type(self.dd): proj = di.proj name = di.name elif type(di) == dict: name = di['dataset'] proj = di['pyproj_Proj'] s = "::: transforming contour coordinates from %s to %s :::" print_text(s % (name, self.dd.name), self.color) x, y = self.longest_cont.T xn, yn = transform(self.dd.proj, proj, x, y) self.longest_cont = array([xn, yn]).T
def __init__(self, dd, fn, direc): """ Generate a mesh with DataInput object <dd>, output filename <fn>, and output directory <direc>. """ self.color = 'grey_46' s = "::: INITIALIZING MESHGENERATOR :::" print_text(s, self.color) self.dd = dd self.fn = fn self.direc = direc self.x, self.y = meshgrid(dd.x, dd.y) if not os.path.exists(direc): os.makedirs(direc) self.f = open(direc + fn + '.geo', 'w') self.fieldList = [] # list of field indexes created.
def finish(self, gui=True, dim=3, out_file_name='mesh'): """ Finish and create the .msh file. If <gui> is True, run the gui program, Otherwise, create the .msh file with dimension <dim> and filename <out_file_name>.msh. """ self.out_file_name = out_file_name #launch the GUI if gui: print_text("::: opening GUI :::", self.color) FlGui.instance().run() # instead of starting the GUI, we could generate the mesh and save it else: s = "::: writing %s.msh :::" % out_file_name print_text(s, self.color) self.m.mesh(dim) self.m.save(out_file_name + ".msh")
def check_dist(self, r): """ remove points in xycoords that are not a linear distance of at least <dist> from previous point. """ lin_dist = lambda p1, p2: sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) edge = self.edge xycoords = self.xycoords n = len(xycoords) mask = ones(n, dtype=bool) i = 0 while (i < n - 1): p1 = xycoords[i] j = i + 1 while (j < n and lin_dist(p1, xycoords[j]) < r): mask[j] = 0 j += 1 i = j # fix end of array i = -1 while(n + i >= 0 and (not mask[i] or \ lin_dist(xycoords[0],xycoords[i]) < r)): mask[i] = 0 i -= 1 #for i in range(0,n-2): # p1 = xycoords[i] # p2 = xycoords[i+1] # if lin_dist(p1, p2) < r: # mask[i] = 0 # print results s = "::: removed %s points closer than %s m to one another :::"% \ (str(len(mask) - sum(mask)), r) print_text(s, self.color) self.xycoords = xycoords[mask]
def convert_to_projection(self): """ """ self.xycoords = [] self.edge = [] p = self.llcoords[0, :] # previous point self.xycoords.append(self.di.get_xy(p[0], p[1])) self.edge.append(True) p_p = self.xycoords[-1] distance = 0 lin_dist = lambda p1, p2: sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) for p in self.llcoords: p_n = self.di.get_xy(p[0], p[1]) # Current point xy delta_X = lin_dist(p_n, p_p) distance += delta_X if delta_X > 500.: # edge points are further apart self.edge.append(True) else: self.edge.append(False) self.xycoords.append(p_n) distance = 0. p_p = p_n """ # remove points at end of array that may overlap while(len(self.xycoords) > 0): self.xycoords.pop() self.edge.pop() """ self.xycoords = array(self.xycoords) self.plot_coords["xycoords"] = self.xycoords #self.clean_edge() #clean (very rare) incorrectly identified edge points self.edge = array(self.edge) s = "::: basin contour created with length %i :::" print_text(s % len(self.xycoords), self.color)
def __init__(self, di, fn, gmsh_file_name): """ Creates a 2D or 3D mesh based on contour .geo file <gmsh_file_name>. Refinements are done on DataInput object <di> with data field index <fn>. """ self.color = '43' s = "::: initializing MeshRefiner on \"%s.geo\" :::" % gmsh_file_name print_text(s, self.color) self.field = di.data[fn].T print_min_max(self.field, 'refinement field [m]') self.spline = RectBivariateSpline(di.x, di.y, self.field, kx=1, ky=1) #load the mesh into a GModel self.m = GModel.current() self.m.load(gmsh_file_name + '.geo') # set some parameters : GmshSetOption("Mesh", "CharacteristicLengthFromPoints", 0.0) GmshSetOption("Mesh", "CharacteristicLengthExtendFromBoundary", 0.0) GmshSetOption("Mesh", "Smoothing", 100.0)
def create_contour(self, var, zero_cntr, skip_pts): """ Create a contour of the data field with index <var> of <dd> provided at initialization. <zero_cntr> is the value of <var> to contour, <skip_pts> is the number of points to skip in the contour, needed to prevent overlap. """ s = "::: creating contour from %s's \"%s\" field with skipping %i " + \ "point(s) :::" print_text(s % (self.dd.name, var, skip_pts), self.color) skip_pts = skip_pts + 1 # create contour : field = self.dd.data[var] fig = figure() self.ax = fig.add_subplot(111) self.ax.set_aspect('equal') self.c = self.ax.contour(self.x, self.y, field, [zero_cntr]) # Get longest contour: cl = self.c.allsegs[0] ind = 0 amax = 0 amax_ind = 0 for a in cl: if size(a) > amax: amax = size(a) amax_ind = ind ind += 1 # remove skip points and last point to avoid overlap : self.longest_cont = cl[amax_ind] s = "::: contour created, length %s nodes :::" print_text(s % shape(self.longest_cont)[0], self.color) self.remove_skip_points(skip_pts)
def eliminate_intersections(self, dist=10): """ Eliminate intersecting boundary elements. <dist> is an integer specifiying how far forward to look to eliminate intersections. If any intersections are found, this method is called recursively until none are found. """ s = "::: eliminating intersections :::" print_text(s, self.color) class Point: def __init__(self, x, y): self.x = x self.y = y def ccw(A, B, C): return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x) def intersect(A, B, C, D): return ccw(A, C, D) != ccw(B, C, D) and ccw(A, B, C) != ccw( A, B, D) lc = self.longest_cont flag = ones(len(lc)) intr = False for ii in range(len(lc) - 1): A = Point(*lc[ii]) B = Point(*lc[ii + 1]) for jj in range(ii, min(ii + dist, len(lc) - 1)): C = Point(*lc[jj]) D = Point(*lc[jj + 1]) if intersect(A, B, C, D) and ii != jj + 1 and ii + 1 != jj: s = " - intersection found between node %i and %i" print_text(s % (ii + 1, jj), 'red') flag[ii + 1] = 0 flag[jj] = 0 intr = True counter = 0 new_cont = zeros((sum(flag), 2)) for ii, fl in enumerate(flag): if fl: new_cont[counter, :] = lc[ii, :] counter += 1 self.longest_cont = new_cont s = "::: eliminated %i nodes :::" print_text(s % sum(flag == 0), self.color) # call again if required : if intr: self.eliminate_intersections(dist)