source: inundation/ga/storm_surge/pyvolution/mesh_factory.py @ 543

Last change on this file since 543 was 543, checked in by ole, 20 years ago

Added circular mesh (not suitable for detailed grids, though)

File size: 14.8 KB
Line 
1"""Library of standard meshes and facilities for reading various
2mesh file formats
3"""
4
5
6def rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
7
8    """Setup a rectangular grid of triangles
9    with m+1 by n+1 grid points
10    and side lengths len1, len2. If side lengths are omitted
11    the mesh defaults to the unit square.
12   
13    len1: x direction (left to right)
14    len2: y direction (bottom to top)
15
16    Return to lists: points and elements suitable for creating a Mesh or
17    FVMesh object, e.g. Mesh(points, elements)
18    """
19
20    from config import epsilon
21   
22    #E = m*n*2        #Number of triangular elements
23    #P = (m+1)*(n+1)  #Number of initial vertices
24
25    delta1 = float(len1)/m
26    delta2 = float(len2)/n   
27
28    #Dictionary of vertex objects
29    vertices = {}
30    points = []
31
32    for i in range(m+1):
33        for j in range(n+1):
34            vertices[i,j] = len(points)
35            points.append([i*delta1 + origin[0], j*delta2 + origin[1]])
36
37
38
39    #Construct 2 triangles per rectangular element and assign tags to boundary
40    elements = []
41    boundary = {}
42    for i in range(m):
43        for j in range(n):
44            v1 = vertices[i,j+1]
45            v2 = vertices[i,j]           
46            v3 = vertices[i+1,j+1]           
47            v4 = vertices[i+1,j]           
48
49            #Update boundary dictionary and create elements
50            if i == m-1:
51                boundary[(len(elements), 2)] = 'right'
52            if j == 0:
53                boundary[(len(elements), 1)] = 'bottom'               
54            elements.append([v4,v3,v2]) #Lower element
55
56            if i == 0:
57                boundary[(len(elements), 2)] = 'left'
58            if j == n-1:
59                boundary[(len(elements), 1)] = 'top' 
60            elements.append([v1,v2,v3]) #Upper element   
61
62    return points, elements, boundary       
63
64
65def oblique(m, n, lenx = 1.0, leny = 1.0, theta = 8.95, origin = (0.0, 0.0)):
66    """Setup a oblique grid of triangles
67    with m segments in the x-direction and n segments in the y-direction
68
69    """
70
71    from Numeric import array
72    import math
73
74    from config import epsilon
75
76
77    deltax = lenx/float(m)
78    deltay = leny/float(n)
79    a = 0.75*lenx*math.tan(theta/180.*math.pi)
80    x1 = lenx
81    y1 = 0
82    x2 = lenx
83    y2 = leny
84    x3 = 0.25*lenx
85    y3 = leny
86    x4 = x3
87    y4 = 0
88    a2 = a/(x1-x4)
89    a1 = -a2*x4
90    a4 = ((a1 + a2*x3)/y3-(a1 + a2*x2)/y2)/(x2-x3)
91    a3 = 1. - (a1 + a2*x3)/y3 - a4*x3
92
93    # Dictionary of vertex objects
94    vertices = {}
95    points = []
96
97    for i in range(m+1):
98        x = deltax*i
99        for j in range(n+1):     
100            y = deltay*j
101            if x > 0.25*lenx:
102                y = a1 + a2*x + a3*y + a4*x*y
103               
104            vertices[i,j] = len(points)
105            points.append([x + origin[0], y + origin[1]])
106
107    # Construct 2 triangles per element       
108    elements = []
109    boundary = {}
110    for i in range(m):
111        for j in range(n):
112            v1 = vertices[i,j+1]
113            v2 = vertices[i,j]           
114            v3 = vertices[i+1,j+1]           
115            v4 = vertices[i+1,j]
116           
117            #Update boundary dictionary and create elements
118            if i == m-1:
119                boundary[(len(elements), 2)] = 'right'
120            if j == 0:
121                boundary[(len(elements), 1)] = 'bottom'               
122            elements.append([v4,v3,v2]) #Lower
123
124            if i == 0:
125                boundary[(len(elements), 2)] = 'left'
126            if j == n-1:
127                boundary[(len(elements), 1)] = 'top' 
128             
129            elements.append([v1,v2,v3]) #Upper
130
131    return points, elements, boundary       
132
133#OLD FORMULA FOR SETTING BOUNDARY TAGS - OBSOLETE NOW             
134#     for id, face in M.boundary:
135
136#         e = element_class.instances[id]
137#         x0, y0, x1, y1, x2, y2 = e.get_instance_vertex_coordinates()
138
139#         if face==2:
140#             #Left or right#
141#             if abs(x0-origin[0]) < epsilon:
142#                 M.boundary[(id,face)] = 'left'           
143#             elif abs(origin[0]+lenx-x0) < epsilon:
144#                 M.boundary[(id,face)] = 'right'
145#             else:
146#                 print face, id, id%m, m, n
147#                 raise 'Left or Right Unknown boundary'                           
148#         elif face==1:
149#             #Top or bottom
150#             if x0 > 0.25*lenx and abs(y0-a1-a2*x0-origin[1]) < epsilon or\
151#                x0 <= 0.25*lenx and abs(y0-origin[1]) < epsilon:           
152#                    M.boundary[(id,face)] = 'bottom'
153#             elif abs(origin[1]+leny-y0) < epsilon:
154#                 M.boundary[(id,face)] = 'top'
155#             else:
156#                 print face, id, id%m, m, n
157#                 raise 'Top or Bottom Unknown boundary' 
158#         else:
159#             print face, id, id%m, m, n
160#             raise 'Unknown boundary'         
161#   
162#     return M
163
164
165
166
167def circular(m, n, radius=1.0, center = (0.0, 0.0)):
168    """Setup a circular grid of triangles with m concentric circles and
169    with n radial segments. If radius is are omitted the mesh defaults to
170    the unit circle radius.
171 
172    radius: radius of circle
173   
174    #FIXME: The triangles become degenerate for large values of m or n.
175    """
176
177
178   
179    from math import pi, cos, sin
180
181    radius = float(radius) #Ensure floating point format
182
183    #Dictionary of vertex objects and list of points
184    vertices = {}
185    points = [[0.0, 0.0]] #Center point
186    vertices[0, 0] = 0
187   
188    for i in range(n):
189        theta = 2*i*pi/n
190        x = cos(theta)
191        y = sin(theta)
192        for j in range(1,m+1):
193            delta = j*radius/m
194            vertices[i,j] = len(points)
195            points.append([delta*x, delta*y])
196
197    #Construct 2 triangles per element       
198    elements = []
199    for i in range(n):
200        for j in range(1,m):
201
202            i1 = (i + 1) % n  #Wrap around 
203           
204            v1 = vertices[i,j+1]
205            v2 = vertices[i,j]           
206            v3 = vertices[i1,j+1]           
207            v4 = vertices[i1,j]
208
209            elements.append([v4,v2,v3]) #Lower               
210            elements.append([v1,v3,v2]) #Upper
211
212
213    #Do the center
214    v1 = vertices[0,0]
215    for i in range(n):
216        i1 = (i + 1) % n  #Wrap around         
217        v2 = vertices[i,1]
218        v3 = vertices[i1,1]
219
220        elements.append([v1,v2,v3]) #center
221         
222    return points, elements
223
224
225def from_polyfile(name):
226    """Read mesh from .poly file, an obj like file format
227    listing first vertex coordinates and then connectivity
228    """
229
230    from util import anglediff
231    from math import pi
232    import os.path
233    root, ext = os.path.splitext(name)
234
235    if ext == 'poly':
236        filename = name
237    else:
238        filename = name + '.poly'
239
240   
241    fid = open(filename)
242
243    points = []    #x, y
244    values = []    #z
245    ##vertex_values = []    #Repeated z   
246    triangles = [] #v0, v1, v2
247   
248    lines = fid.readlines()
249
250    keyword = lines[0].strip()
251    msg = 'First line in .poly file must contain the keyword: POINTS'
252    assert keyword == 'POINTS', msg
253
254    offending = 0
255    i = 1
256    while keyword == 'POINTS':
257        line = lines[i].strip()
258        i += 1
259
260        if line == 'POLYS':
261            keyword = line
262            break
263
264        fields = line.split(':')
265        assert int(fields[0]) == i-1, 'Point indices not consecutive'
266
267        #Split the three floats
268        xyz = fields[1].split()
269
270        x = float(xyz[0])
271        y = float(xyz[1])
272        z = float(xyz[2])       
273
274        points.append([x, y])
275        values.append(z)
276       
277
278    k = i   
279    while keyword == 'POLYS':
280        line = lines[i].strip()
281        i += 1
282
283        if line == 'END':
284            keyword = line
285            break
286       
287
288        fields = line.split(':')
289        assert int(fields[0]) == i-k, 'Poly indices not consecutive'
290
291        #Split the three indices
292        vvv = fields[1].split()
293
294        i0 = int(vvv[0])-1
295        i1 = int(vvv[1])-1
296        i2 = int(vvv[2])-1
297
298        #Check for and exclude degenerate areas
299        x0 = points[i0][0]
300        y0 = points[i0][1]
301        x1 = points[i1][0]
302        y1 = points[i1][1]
303        x2 = points[i2][0]
304        y2 = points[i2][1]               
305
306        area = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
307        if area > 0:
308
309            #Ensure that points are arranged in counter clock-wise order
310            v0 = [x1-x0, y1-y0]
311            v1 = [x2-x1, y2-y1]
312            v2 = [x0-x2, y0-y2]
313
314            a0 = anglediff(v1, v0)
315            a1 = anglediff(v2, v1)
316            a2 = anglediff(v0, v2)       
317
318           
319            if a0 < pi and a1 < pi and a2 < pi:
320                #all is well
321                j0 = i0
322                j1 = i1
323                j2 = i2
324            else:
325                #Swap two vertices
326                j0 = i1
327                j1 = i0
328                j2 = i2
329               
330            triangles.append([j0, j1, j2])
331            ##vertex_values.append([values[j0], values[j1], values[j2]])
332        else:
333            offending +=1 
334
335    print 'Removed %d offending triangles out of %d' %(offending, len(lines))
336    return points, triangles, values
337
338
339
340def strang_mesh(filename):
341    """Read Strang generated mesh.
342    """
343
344    from math import pi
345    from util import anglediff
346   
347   
348    fid = open(filename)
349    points = []    # List of x, y coordinates
350    triangles = [] # List of vertex ids as listed in the file
351   
352    for line in fid.readlines():
353        fields = line.split()
354        if len(fields) == 2:
355            # we are reading vertex coordinates
356            points.append([float(fields[0]), float(fields[1])])
357        elif len(fields) == 3:
358            # we are reading triangle point id's (format ae+b)
359            triangles.append([int(float(fields[0]))-1,
360                              int(float(fields[1]))-1,
361                              int(float(fields[2]))-1])
362        else:
363            raise 'wrong format in ' + filename
364
365    elements = [] #Final list of elements
366
367    for t in triangles:
368        #Get vertex coordinates
369        v0 = t[0]
370        v1 = t[1]
371        v2 = t[2]
372       
373        x0 = points[v0][0]
374        y0 = points[v0][1]
375        x1 = points[v1][0]
376        y1 = points[v1][1]
377        x2 = points[v2][0]
378        y2 = points[v2][1]               
379
380        #Check that points are arranged in counter clock-wise order
381        vec0 = [x1-x0, y1-y0]
382        vec1 = [x2-x1, y2-y1]
383        vec2 = [x0-x2, y0-y2]
384
385        a0 = anglediff(vec1, vec0)
386        a1 = anglediff(vec2, vec1)
387        a2 = anglediff(vec0, vec2)       
388
389        if a0 < pi and a1 < pi and a2 < pi:
390            elements.append([v0, v1, v2])
391        else:
392            elements.append([v0, v2, v1])       
393
394    return points, elements                             
395
396
397
398# def contracting_channel_mesh(m, n, x1 = 0.0, x2 = 1./3., x3 = 2./3., x4 = 1.0,
399#                             y1 =0.0, y4 = -1./4., y8 = 1.0,
400#                              origin = (0.0, 0.0), point_class=Point,
401#                              element_class=Triangle, mesh_class=Mesh):
402#     """Setup a oblique grid of triangles
403#     with m segments in the x-direction and n segments in the y-direction
404
405#     Triangle refers to the actual class or subclass to be instantiated:
406#     e.g. if Volume is a subclass of Triangle,
407#     this function can be invoked with the keywords
408#       oblique_mesh(...,Triangle=Volume, Mesh=Domain)
409#     """
410
411#     from Numeric import array
412#     from visual import rate#
413
414#     import math
415
416#     from config import epsilon
417
418#     E = m*n*2        #Number of triangular elements
419#     P = (m+1)*(n+1)  #Number of initial vertices
420
421#     initialise_consecutive_datastructure(P+E, E,
422#                                          point_class,
423#                                          element_class,
424#                                          mesh_class)
425
426#     deltax = (x4 - x1)/float(m)
427#     deltay = (y8 - y1)/float(n)
428#     a = y4 - y1
429   
430#     if y8 - a <= y1 + a:
431#         print a,y1,y4
432#         raise 'Constriction is too large reduce a'
433           
434#     y2 = y1
435#     y3 = y4
436#     x5 = x4
437#     y5 = y8 - a
438#     x6 = x3
439#     y6 = y5
440#     x7 = x2
441#     y7 = y8
442#     x8 = x1
443   
444#     a2 = a/(x3 - x2)
445#     a1 = a - a*x3/(x3 - x2)
446#     a4 = (-a + a2*(x7 - x6))/(x6 - x7)/y7
447#     a3 = (y7 - a1 - x7*a2 - a4*x7*y7)/y7
448   
449#     # Dictionary of vertex objects
450#     vertices = {}
451
452#     for i in range(m+1):
453#         x = deltax*i
454#         for j in range(n+1):     
455#             y = deltay*j
456#             if x > x2:
457#                 if x < x3:
458#                     y = a1 + a2*x + a3*y + a4*x*y
459#                 else:
460#                     y = a + y*(y5 - y4)/(y8 - y1)   
461               
462#             vertices[i,j] = Point(x + origin[0],y + origin[1])
463
464#     # Construct 2 elements per element       
465#     elements = []
466#     for i in range(m):
467#         for j in range(n):
468#             v1 = vertices[i,j+1]
469#             v2 = vertices[i,j]           
470#             v3 = vertices[i+1,j+1]           
471#             v4 = vertices[i+1,j]
472 
473#             elements.append(element_class(v4,v3,v2)) #Lower               
474#             elements.append(element_class(v1,v2,v3)) #Upper   
475
476#     M = mesh_class(elements)
477
478#     #Set a default tagging
479
480#     for id, face in M.boundary:
481
482#         e = element_class.instances[id]
483#         x_0, y_0, x_1, y_1, x_2, y_2 = e.get_instance_vertex_coordinates()
484#         lenx = x4 - x1
485#         if face==2:
486#             #Left or right#
487#             if abs(x_0-origin[0]) < epsilon:
488#                 M.boundary[(id,face)] = 'left'           
489#             elif abs(origin[0]+lenx-x_0) < epsilon:
490#                 M.boundary[(id,face)] = 'right'
491#             else:
492#                 print face, id, id%m, m, n
493#                 raise 'Left or Right Unknown boundary'                           
494#         elif face==1:
495#             #Top or bottom
496#             if x_0 <= x2 and abs(y_0-y1-origin[1]) < epsilon or\
497#                x_0 > x3 and abs(y_0-y3-origin[1]) < epsilon or\
498#                x_0 >  x2 and x_0 <= x3 and abs(y_0-(y2+(y3-y2)*(x_0-x2)/(x3-x2)+origin[1])) < epsilon:           
499#                 M.boundary[(id,face)] = 'bottom'
500#             elif x_0 <= x7 and abs(y_0-y8-origin[1]) < epsilon or\
501#                x_0 > x6 and abs(y_0-y6-origin[1]) < epsilon or\
502#                x_0 > x7 and x_0 <= x6 and abs(y_0-(y7+(y6-y7)*(x_0-x7)/(x6-x7)+origin[1])) < epsilon:           
503#                 M.boundary[(id,face)] = 'top'
504#             else:
505#                 print face, id, id%m, m, n
506#                 raise 'Top or Bottom Unknown boundary' 
507#         else:
508#             print face, id, id%m, m, n
509#             raise 'Unknown boundary'         
510
511           
512#       #  print id, face, M.boundary[(id,face)],x_0,y_0,x_1,y_1,x_2,y_2
513   
514#     return M
515
516
517
518# #Map from edge number to indices of associated vertices
519# edge_map = ((1,2), (0,2), (0,1))
520
521
522                                         
523   
Note: See TracBrowser for help on using the repository browser.