source: inundation/parallel/pmesh_divide.py @ 2094

Last change on this file since 2094 was 2092, checked in by jack, 19 years ago

pmesh_divide_metis doesn't catch fire anymore when called with n_procs = 1. It now assigns all
the triangles to the one processor. Could probably be made more efficient.

File size: 11.1 KB
Line 
1#########################################################
2#
3#
4#  Read in a data file and subdivide the triangle list
5#
6#
7#  This is only intended as a temporary file, once an
8# automatic grid partitioner has been incorporated this
9# file will become redundant.
10#
11#  Authors: Linda Stals and Matthew Hardy, June 2005
12#  Modified: Linda Stals, Nov 2005
13#            Jack Kelly, Nov 2005
14#
15#
16#########################################################
17
18
19from math import floor
20from Numeric import zeros, Float, Int, reshape
21
22#########################################################
23#
24# If the triangles list is reordered, the quantities
25# assigned to the triangles must also be reorded.
26#
27# *) quantities contain the quantites in the old ordering
28# *) proc_sum[i] contains the number of triangles in
29# processor i
30# *) tri_index is a map from the old triangle ordering to
31# the new ordering, where the new number for triangle
32# i is proc_sum[tri_index[i][0]]+tri_index[i][1]
33#
34# -------------------------------------------------------
35#
36# *) The quantaties are returned in the new ordering
37#
38#########################################################
39
40def reorder(quantities, tri_index, proc_sum):
41
42    # find the number triangles
43
44    N = len(tri_index)
45
46    # temporary storage area
47
48    index = zeros(N, Int)
49    q_reord = {}
50
51    # find the new ordering of the triangles
52
53    for i in range(N):
54        bin = tri_index[i][0]
55        bin_off_set = tri_index[i][1]
56        index[i] = proc_sum[bin]+bin_off_set
57
58    # reorder each quantity according to the new ordering
59
60    for k in quantities:
61        q_reord[k] = zeros((N, 3), Float)
62        for i in range(N):
63            q_reord[k][index[i]]=quantities[k].vertex_values[i]
64    del index
65
66    return q_reord
67
68
69#########################################################
70#
71# Do a simple coordinate based division of the grid
72#
73# *) n_x is the number of subdivisions in the x direction
74# *) n_y is the number of subdivisions in the y direction
75#
76# -------------------------------------------------------
77#
78# *)  The nodes, triangles, boundary, and quantities are
79# returned. triangles_per_proc defines the subdivision.
80# The first triangles_per_proc[0] triangles are assigned
81# to processor 0, the next triangles_per_proc[1] are
82# assigned to processor 1 etc. The boundary and quantites
83# are ordered the same way as the triangles
84#
85#########################################################
86
87def pmesh_divide(domain, n_x = 1, n_y = 1):
88
89    # find the bounding box
90   
91    x_coord_min = domain.xy_extent[0]
92    x_coord_max = domain.xy_extent[2]
93    y_coord_min = domain.xy_extent[1]
94    y_coord_max = domain.xy_extent[3]
95
96    # find the size of each sub-box
97
98    x_div = (x_coord_max-x_coord_min)/n_x
99    y_div = (y_coord_max-y_coord_min)/n_y
100
101    # initialise the lists
102   
103    tri_list = []
104    triangles_per_proc = []
105    proc_sum = []
106    for i in range(n_x*n_y):
107        tri_list.append([])
108        triangles_per_proc.append([])
109        proc_sum.append([])
110        tri_list[i] = []
111
112    # subdivide the triangles depending on which sub-box they sit
113    # in (a triangle sits in the sub-box if its first vectex sits
114    # in that sub-box)
115
116    tri_index = {}
117    N = domain.number_of_elements
118    for i in range(N):
119        t = domain.triangles[i]
120
121        x_coord = domain.centroid_coordinates[i][0]
122        bin_x = int(floor((x_coord-x_coord_min)/x_div))
123        if (bin_x == n_x):
124            bin_x = n_x-1
125
126        y_coord = domain.centroid_coordinates[i][1]
127        bin_y = int(floor((y_coord-y_coord_min)/y_div))
128        if (bin_y == n_y):
129            bin_y = n_y-1
130
131        bin = bin_y*n_x + bin_x
132        tri_list[bin].append(t)
133        tri_index[i] = ([bin, len(tri_list[bin])-1])
134
135    # find the number of triangles per processor and order the
136    # triangle list so that all of the triangles belonging to
137    # processor i are listed before those belonging to processor
138    # i+1
139
140    triangles = []
141    for i in range(n_x*n_y):
142        triangles_per_proc[i] = len(tri_list[i])
143        for t in tri_list[i]:
144            triangles.append(t)
145
146    # the boundary labels have to changed in accoradance with the
147    # new triangle ordering, proc_sum and tri_index help with this
148
149    proc_sum[0] = 0
150    for i in range(n_x*n_y-1):
151        proc_sum[i+1]=proc_sum[i]+triangles_per_proc[i]
152
153    # relabel the boundary elements to fit in with the new triangle
154    # ordering
155
156    boundary = {}
157    for b in domain.boundary:
158        t =  tri_index[b[0]]
159        boundary[proc_sum[t[0]]+t[1], b[1]] = domain.boundary[b]
160
161    quantities = reorder(domain.quantities, tri_index, proc_sum)
162
163    # extract the node list
164   
165    nodes = domain.coordinates.copy()
166    ttriangles = zeros((len(triangles), 3), Int)
167    for i in range(len(triangles)):
168        ttriangles[i] = triangles[i]
169       
170    return nodes, ttriangles, boundary, triangles_per_proc, quantities
171
172
173#########################################################
174#
175# Do a coordinate based division of the grid using the
176# centroid coordinate
177#
178# *) n_x is the number of subdivisions in the x direction
179# *) n_y is the number of subdivisions in the y direction
180#
181# -------------------------------------------------------
182#
183# *)  The nodes, triangles, boundary, and quantities are
184# returned. triangles_per_proc defines the subdivision.
185# The first triangles_per_proc[0] triangles are assigned
186# to processor 0, the next triangles_per_proc[1] are
187# assigned to processor 1 etc. The boundary and quantites
188# are ordered the same way as the triangles
189#
190#########################################################
191def pmesh_divide_steve(domain, n_x = 1, n_y = 1):
192   
193    # find the bounding box
194    x_coord_min = domain.xy_extent[0]
195    x_coord_max = domain.xy_extent[2]
196    y_coord_min = domain.xy_extent[1]
197    y_coord_max = domain.xy_extent[3]
198
199
200    # find the size of each sub-box
201
202    x_div = (x_coord_max-x_coord_min)/n_x
203    y_div = (y_coord_max-y_coord_min)/n_y
204
205
206    # initialise the lists
207    tri_list = []
208    triangles_per_proc = []
209    proc_sum = []
210    for i in range(n_x*n_y):
211        tri_list.append([])
212        triangles_per_proc.append([])
213        proc_sum.append([])
214        tri_list[i] = []
215
216    # subdivide the triangles depending on which sub-box they sit
217    # in (a triangle sits in the sub-box if its first vectex sits
218    # in that sub-box)
219
220    tri_index = {}
221    N = domain.number_of_elements
222 
223    #sort by x coordinate of centroid
224    from Numeric import argsort
225    sort_order = argsort(argsort(domain.centroid_coordinates[:,0]))
226
227    x_div = float(N)/n_x
228
229    for i in range(N):
230        t = domain.triangles[i]
231       
232        bin = int(floor(sort_order[i]/x_div))
233        if (bin == n_x):
234            bin = n_x-1
235
236        tri_list[bin].append(t)
237        tri_index[i] = ([bin, len(tri_list[bin])-1])
238
239    #print tri_list
240    #print tri_index
241
242    # find the number of triangles per processor and order the
243    # triangle list so that all of the triangles belonging to
244    # processor i are listed before those belonging to processor
245    # i+1
246
247    triangles = []
248    for i in range(n_x*n_y):
249        triangles_per_proc[i] = len(tri_list[i])
250        for t in tri_list[i]:
251           triangles.append(t)
252       
253
254    # the boundary labels have to changed in accoradance with the
255    # new triangle ordering, proc_sum and tri_index help with this
256
257    proc_sum[0] = 0
258    for i in range(n_x*n_y-1):
259        proc_sum[i+1]=proc_sum[i]+triangles_per_proc[i]
260
261    # relabel the boundary elements to fit in with the new triangle
262    # ordering
263
264    boundary = {}
265    for b in domain.boundary:
266        t =  tri_index[b[0]]
267        boundary[proc_sum[t[0]]+t[1], b[1]] = domain.boundary[b]
268
269    quantities = reorder(domain.quantities, tri_index, proc_sum)
270
271    # extract the node list
272    nodes = domain.coordinates.copy()
273
274
275    # convert the triangle datastructure to be an array typ
276    # this helps with the communication
277
278    ttriangles = zeros((len(triangles), 3), Int)
279    for i in range(len(triangles)):
280        ttriangles[i] = triangles[i]
281       
282    return nodes, ttriangles, boundary, triangles_per_proc, quantities
283
284
285
286
287###
288#
289# Divide the mesh using a call to metis, through pymetis.
290
291from os import sep
292from sys import path
293
294path.append('..' + sep + 'pymetis')
295
296from metis import partMeshNodal
297
298def pmesh_divide_metis(domain, n_procs):
299    # initialise the lists
300    # List, indexed by processor of # triangles.
301    triangles_per_proc = []
302    # List of lists, indexed by processor of vertex numbers
303    tri_list = []
304    # List indexed by processor of cumulative total of triangles allocated.
305    proc_sum = []
306    for i in range(n_procs):
307        tri_list.append([])
308        triangles_per_proc.append(0)
309        proc_sum.append([])
310
311    # Prepare variables for the metis call
312    n_tri = len(domain.triangles)
313    if n_procs != 1: #Because metis chokes on it...
314        n_vert = len(domain.coordinates)
315        t_list = domain.triangles.copy()
316        t_list = reshape(t_list, (-1,))
317   
318        # The 1 here is for triangular mesh elements.
319        edgecut, epart, npart = partMeshNodal(n_tri, n_vert, t_list, 1, n_procs)
320        del edgecut
321        del npart
322        # print edgecut
323        # print npart
324    else:
325        epart = [0] * n_tri
326
327    # print epart
328
329
330    # Assign triangles to processes, according to what metis told us.
331
332    # tri_index maps triangle number -> processor, new triangle number
333    # (local to the processor)
334    tri_index = {}
335    triangles = []       
336    for i in range(n_tri):
337        triangles_per_proc[epart[i]] = triangles_per_proc[epart[i]] + 1
338        tri_list[epart[i]].append(domain.triangles[i])
339        tri_index[i] = ([epart[i], len(tri_list[epart[i]]) - 1])
340
341    # print tri_list
342    # print triangles_per_proc
343
344    # order the triangle list so that all of the triangles belonging
345    # to processor i are listed before those belonging to processor
346    # i+1
347
348    for i in range(n_procs):
349        for t in tri_list[i]:
350            triangles.append(t)
351           
352    # the boundary labels have to changed in accoradance with the
353    # new triangle ordering, proc_sum and tri_index help with this
354
355    proc_sum[0] = 0
356    for i in range(n_procs - 1):
357        proc_sum[i+1]=proc_sum[i]+triangles_per_proc[i]
358
359    # relabel the boundary elements to fit in with the new triangle
360    # ordering
361
362    boundary = {}
363    for b in domain.boundary:
364        t =  tri_index[b[0]]
365        boundary[proc_sum[t[0]]+t[1], b[1]] = domain.boundary[b]
366
367    quantities = reorder(domain.quantities, tri_index, proc_sum)
368
369    # extract the node list
370    nodes = domain.coordinates.copy()
371
372    # convert the triangle datastructure to be an array type
373    # this helps with the communication
374
375    ttriangles = zeros((len(triangles), 3), Int)
376    for i in range(len(triangles)):
377        ttriangles[i] = triangles[i]
378       
379    return nodes, ttriangles, boundary, triangles_per_proc, quantities
Note: See TracBrowser for help on using the repository browser.