def create_gmsh_geo(shpfile, scalefile, geofile, startpoly=0, ndmin=8, scalefac=1.0,\ r=1.08, lcmax=2000.0, sigmoid=0,\ linetype='BSpline'): """ Generate a gmsh *.geo file using a boundary from a shpfile Inputs: --- - shpfile : a polygon shapefile with the domain boundaries. Make sure that the first polygon is the outer ring. If not change 'startpoly' parameter. - scalefile : a line shapefile with field 'scale' specifying the target grid resolution for that region. - geofile: output geo ascii file. *Optional* - startpoly [default=0] - the index of the outer polygon in the shapefile. - ndmin [default=8] - the minimum range of the scale = ndmin*scale - r : expansion factor - lcmax [default=2000] - the maximum grid cell size. - sigmoid [default=0] - linetype - 'BSpline' or 'Line' """ # Load the polygon shape file xy, field = readShpPoly(shpfile, FIELDNAME='FID') # Load the scale shape file xyscale, scale = readShpPointLine(scalefile, FIELDNAME='scale') # Load the 'embed' flag to see if the scale layer should be embedded #try: # exyscale,embed = readShpPointLine(scalefile,FIELDNAME='embed') #except: # print 'Warning - could not find "embed" field in shapefile. Setting embed = 0.' # embed = [ss*0 for ss in scale] exyscale, embed = readShpPointLine(scalefile, FIELDNAME='embed') if embed == []: embed = [ss * 0 for ss in scale] ## output geo and svg file fgeo = open(geofile, 'w') fgeo.write("""IP = newp; IL = newl; IS = news; IF = newf; """) ip = 0 # Point counter il = 0 # Line counter rp = 0 lines = [] for loop in xy: firstp = ip for p in range(loop.shape[0]): rp = rp + 1 fgeo.write("Point(IP + %i) = {%.16e, %.16e, %.16e}; // %i\n" % (ip, loop[p, 0], loop[p, 1], 0., rp - 1)) ip = ip + 1 if linetype == 'Line' and ip > 1: fgeo.write("Line(IL + %i) = {IP + %i , IP + %i};\n" % \ (il, ip-2, ip-1)) il = il + 1 lines.append(il - 1) if linetype == 'BSpline': fgeo.write("BSpline(IL + %i) = {IP + %i : IP + %i, IP + %i};\n" % \ (il, firstp, ip - 1, firstp)) il = il + 1 lines.append(il - 1) # Create the surface polygon fgeo.write('\n//%s\n//Surface Polygon Definition\n//%s\n\n' % (72 * '#', 72 * '#')) surfstart = il fgeo.write("Line Loop(IL + %i) = {IL + %s};\n" % (il, startpoly)) il += 1 for ll in lines: if ll != startpoly: fgeo.write("Line Loop(IL + %i) = {IL + %s};\n" % (il, ll)) il += 1 surfend = il - 1 fgeo.write("Plane Surface(IL + %i) = {IL + %i : IL + %i};\n" % (il, surfstart, surfend)) fgeo.write('Physical Surface("Ocean") = {IL + %i};\n' % il) surface_id = il # Keep this to embed lines into il += 1 # Create the grid scale lines and fields fgeo.write('\n//%s\n//Grid Scale Definition\n//%s\n\n' % (72 * '#', 72 * '#')) slines = [] # Reference to scale lines for loop, ss, ee in zip(xyscale, scale, embed): firstp = ip ss *= scalefac # Applies scale factor for p in range(loop.shape[0]): rp = rp + 1 #fgeo.write("Point(IP + %i) = {%.16e, %.16e, %.16e}; // %i\n" % (ip, loop[p,0], loop[p,1], 0., rp -1)) fgeo.write( "Point(IP + %i) = {%.16e, %.16e, %.16e,%.16e}; // %i\n" % (ip, loop[p, 0], loop[p, 1], 0., rp - 1, float(ss))) ip = ip + 1 if ee: #fgeo.write("BSpline(IL + %i) = {IP + %i : IP + %i};\n" % (il, firstp, ip - 1)) fgeo.write("%s(IL + %i) = {IP + %i : IP + %i};\n" % (linetpye, il, firstp, ip - 1)) # Embed this line in the main surface so that cells are aligned fgeo.write("Line{IL + %i} In Surface{IL + %i};\n" % (il, surface_id)) else: # Don't embed (can set as BSpline) fgeo.write("%s(IL + %i) = {IP + %i : IP + %i};\n" % (linetype, il, firstp, ip - 1)) slines.append(il) il = il + 1 ifield = 0 # Field counter fids = [] ii = 0 for ss, line in zip(scale, slines): fgeo.write("Field[IF + %i] = Attractor;\n" % ifield) fgeo.write("Field[IF + %i].EdgesList = {IL + %i};\n" % (ifield, line)) nodesperedge = get_nnodes_from_line(xyscale[ii], 2.0 * float(ss)) fgeo.write("Field[IF + %i].NNodesByEdge = %i;\n" % (ifield, nodesperedge)) ifield += 1 fgeo.write("Field[IF + %i] = Threshold;\n" % ifield) # Find the maximum distance Nk = np.log(lcmax / ss) / np.log(r) print(ss, Nk) lmin = float(ndmin) * float(ss) lmax = lmin + Nk * ss fgeo.write("Field[IF + %i].DistMax = %6.2f;\n" % (ifield, lmax)) fgeo.write("Field[IF + %i].DistMin = %6.2f;\n" % (ifield, lmin)) fgeo.write("Field[IF + %i].IField = IF + %i;\n" % (ifield, ifield - 1)) fgeo.write("Field[IF + %i].LcMax = %6.2f;\n" % (ifield, lcmax)) fgeo.write("Field[IF + %i].LcMin = %6.2f;\n" % (ifield, float(ss))) fgeo.write("Field[IF + %i].Sigmoid = %d;\n" % (ifield, sigmoid)) fids.append(ifield) ifield += 1 ii += 1 fieldlist = '{' for ff in fids: fieldlist += 'IF + %d, ' % ff fieldlist = fieldlist[:-2] + '}' fgeo.write("Field[IF + %i] = Min;\n" % ifield) fgeo.write("Field[IF + %i].FieldsList = %s;\n" % (ifield, fieldlist)) fgeo.write("Background Field = IF + %i;\n" % ifield) # Set Quad options by default fgeo.write("Mesh.CharacteristicLengthMax=%.16e;//Max cell size\n" % lcmax) fgeo.write("Mesh.RecombineAll=0;//recombine all defined surfaces\n") fgeo.write("Mesh.Algorithm=6;//front\n") fgeo.write("Mesh.Smoothing=10;//10 smoothing steps\n") fgeo.write("Mesh.Remove4Triangles = 1;\n") fgeo.close() print('Complete. GMSH geo file written to:\n\t %s' % geofile)
def create_gmsh_geo(shpfile, scalefile, geofile, startpoly=0, ndmin=8, scalefac=1.0,\ r=1.08, lcmax=2000.0, sigmoid=0,\ linetype='BSpline'): """ Generate a gmsh *.geo file using a boundary from a shpfile Inputs: --- - shpfile : a polygon shapefile with the domain boundaries. Make sure that the first polygon is the outer ring. If not change 'startpoly' parameter. - scalefile : a line shapefile with field 'scale' specifying the target grid resolution for that region. - geofile: output geo ascii file. *Optional* - startpoly [default=0] - the index of the outer polygon in the shapefile. - ndmin [default=8] - the minimum range of the scale = ndmin*scale - r : expansion factor - lcmax [default=2000] - the maximum grid cell size. - sigmoid [default=0] - linetype - 'BSpline' or 'Line' """ # Load the polygon shape file xy,field = readShpPoly(shpfile,FIELDNAME='FID') # Load the scale shape file xyscale,scale = readShpPointLine(scalefile,FIELDNAME='scale') # Load the 'embed' flag to see if the scale layer should be embedded #try: # exyscale,embed = readShpPointLine(scalefile,FIELDNAME='embed') #except: # print 'Warning - could not find "embed" field in shapefile. Setting embed = 0.' # embed = [ss*0 for ss in scale] exyscale,embed = readShpPointLine(scalefile,FIELDNAME='embed') if embed == []: embed = [ss*0 for ss in scale] ## output geo and svg file fgeo = open(geofile,'w') fgeo.write("""IP = newp; IL = newl; IS = news; IF = newf; """ ) ip = 0 # Point counter il = 0 # Line counter rp = 0 lines=[] for loop in xy: firstp = ip for p in range(loop.shape[0]): rp = rp + 1 fgeo.write("Point(IP + %i) = {%.16e, %.16e, %.16e}; // %i\n" % (ip, loop[p,0], loop[p,1], 0., rp -1)) ip = ip + 1 if linetype == 'Line' and ip > 1: fgeo.write("Line(IL + %i) = {IP + %i , IP + %i};\n" % \ (il, ip-2, ip-1)) il = il + 1 lines.append(il-1) if linetype =='BSpline': fgeo.write("BSpline(IL + %i) = {IP + %i : IP + %i, IP + %i};\n" % \ (il, firstp, ip - 1, firstp)) il = il + 1 lines.append(il-1) # Create the surface polygon fgeo.write('\n//%s\n//Surface Polygon Definition\n//%s\n\n'%(72*'#',72*'#')) surfstart=il fgeo.write("Line Loop(IL + %i) = {IL + %s};\n" % (il,startpoly) ) il += 1 for ll in lines: if ll != startpoly: fgeo.write("Line Loop(IL + %i) = {IL + %s};\n" % (il,ll) ) il += 1 surfend = il - 1 fgeo.write("Plane Surface(IL + %i) = {IL + %i : IL + %i};\n"%(il,surfstart,surfend)) fgeo.write('Physical Surface("Ocean") = {IL + %i};\n'%il) surface_id = il # Keep this to embed lines into il += 1 # Create the grid scale lines and fields fgeo.write('\n//%s\n//Grid Scale Definition\n//%s\n\n'%(72*'#',72*'#')) slines=[] # Reference to scale lines for loop,ss,ee in zip(xyscale,scale,embed): firstp = ip ss *= scalefac # Applies scale factor for p in range(loop.shape[0]): rp = rp + 1 #fgeo.write("Point(IP + %i) = {%.16e, %.16e, %.16e}; // %i\n" % (ip, loop[p,0], loop[p,1], 0., rp -1)) fgeo.write("Point(IP + %i) = {%.16e, %.16e, %.16e,%.16e}; // %i\n" % (ip, loop[p,0], loop[p,1], 0., rp -1,float(ss))) ip = ip + 1 if ee: #fgeo.write("BSpline(IL + %i) = {IP + %i : IP + %i};\n" % (il, firstp, ip - 1)) fgeo.write("%s(IL + %i) = {IP + %i : IP + %i};\n" % (linetpye,il, firstp, ip - 1)) # Embed this line in the main surface so that cells are aligned fgeo.write("Line{IL + %i} In Surface{IL + %i};\n"%(il,surface_id)) else: # Don't embed (can set as BSpline) fgeo.write("%s(IL + %i) = {IP + %i : IP + %i};\n" % (linetype,il, firstp, ip - 1)) slines.append(il) il = il + 1 ifield = 0 # Field counter fids = [] ii=0 for ss,line in zip(scale,slines): fgeo.write("Field[IF + %i] = Attractor;\n"%ifield) fgeo.write("Field[IF + %i].EdgesList = {IL + %i};\n"%(ifield,line)) nodesperedge = get_nnodes_from_line(xyscale[ii],2.0*float(ss)) fgeo.write("Field[IF + %i].NNodesByEdge = %i;\n"%(ifield,nodesperedge)) ifield+=1 fgeo.write("Field[IF + %i] = Threshold;\n"%ifield) # Find the maximum distance Nk = np.log(lcmax/ss)/np.log(r) print ss,Nk lmin = float(ndmin)*float(ss) lmax = lmin + Nk * ss fgeo.write("Field[IF + %i].DistMax = %6.2f;\n"%(ifield,lmax)) fgeo.write("Field[IF + %i].DistMin = %6.2f;\n"%(ifield,lmin)) fgeo.write("Field[IF + %i].IField = IF + %i;\n"%(ifield,ifield-1)) fgeo.write("Field[IF + %i].LcMax = %6.2f;\n"%(ifield,lcmax)) fgeo.write("Field[IF + %i].LcMin = %6.2f;\n"%(ifield,float(ss))) fgeo.write("Field[IF + %i].Sigmoid = %d;\n"%(ifield,sigmoid)) fids.append(ifield) ifield+=1 ii+=1 fieldlist = '{' for ff in fids: fieldlist += 'IF + %d, '%ff fieldlist = fieldlist[:-2]+'}' fgeo.write("Field[IF + %i] = Min;\n"%ifield) fgeo.write("Field[IF + %i].FieldsList = %s;\n"%(ifield,fieldlist)) fgeo.write("Background Field = IF + %i;\n"%ifield) # Set Quad options by default fgeo.write("Mesh.CharacteristicLengthMax=%.16e;//Max cell size\n"%lcmax) fgeo.write("Mesh.RecombineAll=0;//recombine all defined surfaces\n") fgeo.write("Mesh.Algorithm=6;//front\n") fgeo.write("Mesh.Smoothing=10;//10 smoothing steps\n") fgeo.write("Mesh.Remove4Triangles = 1;\n") fgeo.close() print 'Complete. GMSH geo file written to:\n\t %s'%geofile
def create_pos_file(posfile,scalefile, xlims,ylims,dx,\ geofile=None,ndmin=5, lcmax=2000.,r=1.05, scalefac=1.0): """ Generates a gmsh background scale file (*.pos) If a geofile is specified the mesh is embedded """ from shapely import geometry, speedups import pandas as pd if speedups.available: speedups.enable() X, Y = np.meshgrid(np.arange(xlims[0], xlims[1], dx), np.arange(ylims[0], ylims[1], dx)) xy = np.vstack((X.ravel(), Y.ravel())).T Np = xy.shape[0] nj, ni = X.shape # Load the scalefile xyscale, gridscale = readShpPointLine(scalefile, FIELDNAME='scale') # Load all of the points into shapely type geometry # Distance method won't work with numpy array #P = geometry.asPoint(xy) P = [geometry.Point(xy[i, 0], xy[i, 1]) for i in range(Np)] L = [] for ll in xyscale: L.append(geometry.asLineString(ll)) # Vectorize operations using pandas geo_points = pd.DataFrame({'single_column':xy.tolist()}).single_column.\ apply(lambda x: geometry.Point(x[0],x[1])).values geo_lines = pd.DataFrame({'single_column':xyscale}).single_column.\ apply(lambda x: geometry.LineString(x)).values def distance(a_point, a_line): return a_point.distance(a_line) distance_vec = np.vectorize(distance) dist_all = distance_vec(geo_points[..., np.newaxis], geo_lines) nlines = len(L) scale_all = np.zeros((nj, ni, nlines)) for n in range(nlines): print('Calculating distance from line %d...' % n) ss = gridscale[n] * scalefac lmin = ndmin * ss # Find the maximum distance Nk = np.log(lcmax / ss) / np.log(r) print(ss, Nk) lmax = lmin + Nk * ss #dist = [L[n].distance(P[i]) for i in range(Np)] #dist = np.array(dist).reshape((nj,ni)) dist = dist_all[:, n].reshape((nj, ni)) # Calculate the scale N = (dist - lmin) / ss scale = ss * r**N ind = dist <= lmin if ind.any(): scale[ind] = ss ind = scale > lcmax if ind.any(): scale[ind] = lcmax scale_all[:, :, n] = scale scale_min = scale_all.min(axis=-1) write_pos_file(posfile, X, Y, scale_min) if not geofile is None: fgeo = open(geofile, 'a') fgeo.write( "// Merge a post-processing view containing the target mesh sizes\n" ) fgeo.write('Merge "%s";' % posfile) fgeo.write("// Apply the view as the current background mesh\n") fgeo.write("Background Mesh View[0];\n") fgeo.close()
def create_pos_file(posfile,scalefile, xlims,ylims,dx,\ geofile=None,ndmin=5, lcmax=2000.,r=1.05, scalefac=1.0): """ Generates a gmsh background scale file (*.pos) If a geofile is specified the mesh is embedded """ from shapely import geometry, speedups import pandas as pd if speedups.available: speedups.enable() X,Y = np.meshgrid(np.arange(xlims[0],xlims[1],dx),np.arange(ylims[0],ylims[1],dx)) xy = np.vstack((X.ravel(),Y.ravel())).T Np = xy.shape[0] nj,ni=X.shape # Load the scalefile xyscale,gridscale = readShpPointLine(scalefile,FIELDNAME='scale') # Load all of the points into shapely type geometry # Distance method won't work with numpy array #P = geometry.asPoint(xy) P = [geometry.Point(xy[i,0],xy[i,1]) for i in range(Np)] L=[] for ll in xyscale: L.append(geometry.asLineString(ll)) # Vectorize operations using pandas geo_points = pd.DataFrame({'single_column':xy.tolist()}).single_column.\ apply(lambda x: geometry.Point(x[0],x[1])).values geo_lines = pd.DataFrame({'single_column':xyscale}).single_column.\ apply(lambda x: geometry.LineString(x)).values def distance(a_point, a_line): return a_point.distance(a_line) distance_vec = np.vectorize(distance) dist_all = distance_vec(geo_points[...,np.newaxis], geo_lines) nlines = len(L) scale_all = np.zeros((nj,ni,nlines)) for n in range(nlines): print 'Calculating distance from line %d...'%n ss = gridscale[n] * scalefac lmin = ndmin * ss # Find the maximum distance Nk = np.log(lcmax/ss)/np.log(r) print ss,Nk lmax = lmin + Nk * ss #dist = [L[n].distance(P[i]) for i in range(Np)] #dist = np.array(dist).reshape((nj,ni)) dist = dist_all[:,n].reshape((nj,ni)) # Calculate the scale N = (dist-lmin)/ss scale = ss*r**N ind = dist<=lmin if ind.any(): scale[ind] = ss ind = scale>lcmax if ind.any(): scale[ind] = lcmax scale_all[:,:,n] = scale scale_min = scale_all.min(axis=-1) write_pos_file(posfile,X,Y,scale_min) if not geofile is None: fgeo = open(geofile,'a') fgeo.write("// Merge a post-processing view containing the target mesh sizes\n") fgeo.write('Merge "%s";'%posfile) fgeo.write("// Apply the view as the current background mesh\n") fgeo.write("Background Mesh View[0];\n") fgeo.close()