source: branches/Numeric_anuga_source/anuga_parallel/pmesh_divide.py @ 7952

Last change on this file since 7952 was 6721, checked in by steve, 16 years ago

Debugging parallel test function

File size: 6.1 KB
Line 
1#########################################################
2#
3#
4#  Read in a data file and subdivide the triangle list
5#
6#
7#  The final routine, pmesh_divide_metis, does automatic
8# grid partitioning. Once testing has finished on this
9# routine the others should be removed.
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
18from os import sep
19from sys import path
20from math import floor
21
22from Numeric import zeros, Float, Int, reshape, argsort, ArrayType
23
24
25#########################################################
26#
27# If the triangles list is reordered, the quantities
28# assigned to the triangles must also be reorded.
29#
30# *) quantities contain the quantites in the old ordering
31# *) proc_sum[i] contains the number of triangles in
32# processor i
33# *) tri_index is a map from the old triangle ordering to
34# the new ordering, where the new number for triangle
35# i is proc_sum[tri_index[i][0]]+tri_index[i][1]
36#
37# -------------------------------------------------------
38#
39# *) The quantaties are returned in the new ordering
40#
41#########################################################
42
43def reorder(quantities, tri_index, proc_sum):
44
45    # Find the number triangles
46
47    N = len(tri_index)
48
49    # Temporary storage area
50
51    index = zeros(N, Int)
52    q_reord = {}
53
54    # Find the new ordering of the triangles
55
56    for i in range(N):
57        bin = tri_index[i][0]
58        bin_off_set = tri_index[i][1]
59        index[i] = proc_sum[bin]+bin_off_set
60
61    # Reorder each quantity according to the new ordering
62
63    for k in quantities:
64        q_reord[k] = zeros((N, 3), Float)
65        for i in range(N):
66            q_reord[k][index[i]]=quantities[k].vertex_values[i]
67    del index
68
69    return q_reord
70
71
72#########################################################
73#
74# Divide the mesh using a call to metis, through pymetis.
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
87#path.append('..' + sep + 'pymetis')
88
89try:
90   
91    from pymetis.metis import partMeshNodal
92except ImportError:
93    print "***************************************************"
94    print "         Metis is probably not compiled."
95    print "         Read \anuga_core\source\pymetis\README"
96    print "***************************************************"
97    raise ImportError
98def pmesh_divide_metis(domain, n_procs):
99   
100    # Initialise the lists
101    # List, indexed by processor of # triangles.
102   
103    triangles_per_proc = []
104   
105    # List of lists, indexed by processor of vertex numbers
106   
107    tri_list = []
108   
109    # List indexed by processor of cumulative total of triangles allocated.
110   
111    proc_sum = []
112    for i in range(n_procs):
113        tri_list.append([])
114        triangles_per_proc.append(0)
115        proc_sum.append([])
116
117    # Prepare variables for the metis call
118   
119    n_tri = len(domain.triangles)
120    if n_procs != 1: #Because metis chokes on it...
121        n_vert = domain.get_number_of_nodes()
122        t_list = domain.triangles.copy()
123        t_list = reshape(t_list, (-1,))
124   
125        # The 1 here is for triangular mesh elements.
126        edgecut, epart, npart = partMeshNodal(n_tri, n_vert, t_list, 1, n_procs)
127        # print edgecut
128        # print npart
129        # print epart
130        del edgecut
131        del npart
132
133        # Sometimes (usu. on x86_64), partMeshNodal returnes an array of zero
134        # dimensional arrays. Correct this.
135        if type(epart[0]) == ArrayType:
136            epart_new = zeros(len(epart), Int)
137            for i in range(len(epart)):
138                epart_new[i] = epart[i][0]
139            epart = epart_new
140            del epart_new
141        # Assign triangles to processes, according to what metis told us.
142       
143        # tri_index maps triangle number -> processor, new triangle number
144        # (local to the processor)
145       
146        tri_index = {}
147        triangles = []       
148        for i in range(n_tri):
149            triangles_per_proc[epart[i]] = triangles_per_proc[epart[i]] + 1
150            tri_list[epart[i]].append(domain.triangles[i])
151            tri_index[i] = ([epart[i], len(tri_list[epart[i]]) - 1])
152       
153        # Order the triangle list so that all of the triangles belonging
154        # to processor i are listed before those belonging to processor
155        # i+1
156
157        for i in range(n_procs):
158            for t in tri_list[i]:
159                triangles.append(t)
160           
161        # The boundary labels have to changed in accoradance with the
162        # new triangle ordering, proc_sum and tri_index help with this
163
164        proc_sum[0] = 0
165        for i in range(n_procs - 1):
166            proc_sum[i+1]=proc_sum[i]+triangles_per_proc[i]
167
168        # Relabel the boundary elements to fit in with the new triangle
169        # ordering
170
171        boundary = {}
172        for b in domain.boundary:
173            t =  tri_index[b[0]]
174            boundary[proc_sum[t[0]]+t[1], b[1]] = domain.boundary[b]
175
176        quantities = reorder(domain.quantities, tri_index, proc_sum)
177    else:
178        boundary = domain.boundary.copy()
179        triangles_per_proc[0] = n_tri
180        triangles = domain.triangles.copy()
181       
182        # This is essentially the same as a chunk of code from reorder.
183       
184        quantities = {}
185        for k in domain.quantities:
186            quantities[k] = zeros((n_tri, 3), Float)
187            for i in range(n_tri):
188                quantities[k][i] = domain.quantities[k].vertex_values[i]
189       
190    # Extract the node list
191   
192    nodes = domain.get_nodes().copy()
193   
194    # Convert the triangle datastructure to be an array type,
195    # this helps with the communication
196
197    ttriangles = zeros((len(triangles), 3), Int)
198    for i in range(len(triangles)):
199        ttriangles[i] = triangles[i]
200   
201    return nodes, ttriangles, boundary, triangles_per_proc, quantities
Note: See TracBrowser for help on using the repository browser.