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

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

Implemented xya2rectangular and tested it

File size: 9.5 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
134def circular(m, n, radius=1.0, center = (0.0, 0.0)):
135    """Setup a circular grid of triangles with m concentric circles and
136    with n radial segments. If radius is are omitted the mesh defaults to
137    the unit circle radius.
138 
139    radius: radius of circle
140   
141    #FIXME: The triangles become degenerate for large values of m or n.
142    """
143
144
145   
146    from math import pi, cos, sin
147
148    radius = float(radius) #Ensure floating point format
149
150    #Dictionary of vertex objects and list of points
151    vertices = {}
152    points = [[0.0, 0.0]] #Center point
153    vertices[0, 0] = 0
154   
155    for i in range(n):
156        theta = 2*i*pi/n
157        x = cos(theta)
158        y = sin(theta)
159        for j in range(1,m+1):
160            delta = j*radius/m
161            vertices[i,j] = len(points)
162            points.append([delta*x, delta*y])
163
164    #Construct 2 triangles per element       
165    elements = []
166    for i in range(n):
167        for j in range(1,m):
168
169            i1 = (i + 1) % n  #Wrap around 
170           
171            v1 = vertices[i,j+1]
172            v2 = vertices[i,j]           
173            v3 = vertices[i1,j+1]           
174            v4 = vertices[i1,j]
175
176            elements.append([v4,v2,v3]) #Lower               
177            elements.append([v1,v3,v2]) #Upper
178
179
180    #Do the center
181    v1 = vertices[0,0]
182    for i in range(n):
183        i1 = (i + 1) % n  #Wrap around         
184        v2 = vertices[i,1]
185        v3 = vertices[i1,1]
186
187        elements.append([v1,v2,v3]) #center
188         
189    return points, elements
190
191
192def from_polyfile(name):
193    """Read mesh from .poly file, an obj like file format
194    listing first vertex coordinates and then connectivity
195    """
196
197    from util import anglediff
198    from math import pi
199    import os.path
200    root, ext = os.path.splitext(name)
201
202    if ext == 'poly':
203        filename = name
204    else:
205        filename = name + '.poly'
206
207   
208    fid = open(filename)
209
210    points = []    #x, y
211    values = []    #z
212    ##vertex_values = []    #Repeated z   
213    triangles = [] #v0, v1, v2
214   
215    lines = fid.readlines()
216
217    keyword = lines[0].strip()
218    msg = 'First line in .poly file must contain the keyword: POINTS'
219    assert keyword == 'POINTS', msg
220
221    offending = 0
222    i = 1
223    while keyword == 'POINTS':
224        line = lines[i].strip()
225        i += 1
226
227        if line == 'POLYS':
228            keyword = line
229            break
230
231        fields = line.split(':')
232        assert int(fields[0]) == i-1, 'Point indices not consecutive'
233
234        #Split the three floats
235        xyz = fields[1].split()
236
237        x = float(xyz[0])
238        y = float(xyz[1])
239        z = float(xyz[2])       
240
241        points.append([x, y])
242        values.append(z)
243       
244
245    k = i   
246    while keyword == 'POLYS':
247        line = lines[i].strip()
248        i += 1
249
250        if line == 'END':
251            keyword = line
252            break
253       
254
255        fields = line.split(':')
256        assert int(fields[0]) == i-k, 'Poly indices not consecutive'
257
258        #Split the three indices
259        vvv = fields[1].split()
260
261        i0 = int(vvv[0])-1
262        i1 = int(vvv[1])-1
263        i2 = int(vvv[2])-1
264
265        #Check for and exclude degenerate areas
266        x0 = points[i0][0]
267        y0 = points[i0][1]
268        x1 = points[i1][0]
269        y1 = points[i1][1]
270        x2 = points[i2][0]
271        y2 = points[i2][1]               
272
273        area = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
274        if area > 0:
275
276            #Ensure that points are arranged in counter clock-wise order
277            v0 = [x1-x0, y1-y0]
278            v1 = [x2-x1, y2-y1]
279            v2 = [x0-x2, y0-y2]
280
281            a0 = anglediff(v1, v0)
282            a1 = anglediff(v2, v1)
283            a2 = anglediff(v0, v2)       
284
285           
286            if a0 < pi and a1 < pi and a2 < pi:
287                #all is well
288                j0 = i0
289                j1 = i1
290                j2 = i2
291            else:
292                #Swap two vertices
293                j0 = i1
294                j1 = i0
295                j2 = i2
296               
297            triangles.append([j0, j1, j2])
298            ##vertex_values.append([values[j0], values[j1], values[j2]])
299        else:
300            offending +=1 
301
302    print 'Removed %d offending triangles out of %d' %(offending, len(lines))
303    return points, triangles, values
304
305
306
307def strang_mesh(filename):
308    """Read Strang generated mesh.
309    """
310
311    from math import pi
312    from util import anglediff
313   
314   
315    fid = open(filename)
316    points = []    # List of x, y coordinates
317    triangles = [] # List of vertex ids as listed in the file
318   
319    for line in fid.readlines():
320        fields = line.split()
321        if len(fields) == 2:
322            # we are reading vertex coordinates
323            points.append([float(fields[0]), float(fields[1])])
324        elif len(fields) == 3:
325            # we are reading triangle point id's (format ae+b)
326            triangles.append([int(float(fields[0]))-1,
327                              int(float(fields[1]))-1,
328                              int(float(fields[2]))-1])
329        else:
330            raise 'wrong format in ' + filename
331
332    elements = [] #Final list of elements
333
334    for t in triangles:
335        #Get vertex coordinates
336        v0 = t[0]
337        v1 = t[1]
338        v2 = t[2]
339       
340        x0 = points[v0][0]
341        y0 = points[v0][1]
342        x1 = points[v1][0]
343        y1 = points[v1][1]
344        x2 = points[v2][0]
345        y2 = points[v2][1]               
346
347        #Check that points are arranged in counter clock-wise order
348        vec0 = [x1-x0, y1-y0]
349        vec1 = [x2-x1, y2-y1]
350        vec2 = [x0-x2, y0-y2]
351
352        a0 = anglediff(vec1, vec0)
353        a1 = anglediff(vec2, vec1)
354        a2 = anglediff(vec0, vec2)       
355
356        if a0 < pi and a1 < pi and a2 < pi:
357            elements.append([v0, v1, v2])
358        else:
359            elements.append([v0, v2, v1])       
360
361    return points, elements                             
362
363# #Map from edge number to indices of associated vertices
364# edge_map = ((1,2), (0,2), (0,1))
365
366
367                                         
368   
Note: See TracBrowser for help on using the repository browser.