source: inundation/parallel/build_submesh.py @ 1855

Last change on this file since 1855 was 1580, checked in by linda, 19 years ago

communicate quantities in parallel

File size: 13.5 KB
Line 
1
2
3import sys
4from mesh import *
5from Numeric import array, zeros, Float
6
7#########################################################
8#
9# Subdivide the triangles into non-overlapping domains.
10#
11#  *)  The subdivision is controlled by triangles_per_proc.
12# The first triangles_per_proc[0] triangles are assigned
13# to the first processor, the second triangles_per_proc[1]
14# are assigned to the second processor etc.
15#
16#  *) nodes, triangles and boundary contains all of the
17# nodes, triangles and boundary tag information for the
18# whole domain. The triangles should be orientated in the
19# correct way and the nodes number consecutively from 0.
20#
21# -------------------------------------------------------
22#
23#  *) A dictionary containing the full_nodes, full_triangles
24# and full_boundary information for each processor is
25# returned. The node information consists of
26# [global_id, x_coord, y_coord].
27#
28#########################################################
29
30def submesh_full(nodes, triangles, boundary, triangles_per_proc):
31
32    # initialise
33
34    tlower = 0
35    nproc = len(triangles_per_proc)
36    nnodes = len(nodes)
37    node_list = []
38    triangle_list = []
39    boundary_list = []
40    submesh = {}
41
42    # loop over processors
43
44    for p in range(nproc):
45
46        # find triangles on processor p
47
48        tupper = triangles_per_proc[p]+tlower
49        subtriangles = triangles[tlower:tupper]
50        triangle_list.append(subtriangles)
51
52        # find the boundary edges on processor p
53       
54        subboundary = {}
55        for k in boundary:
56            if (k[0] >=tlower and k[0] < tupper):
57                subboundary[k]=boundary[k]
58        boundary_list.append(subboundary)
59
60        #
61        # find nodes in processor p
62
63        nodemap = map(lambda n: 0, nodes)
64        for t in subtriangles:
65            nodemap[t[0]]=1
66            nodemap[t[1]]=1
67            nodemap[t[2]]=1
68        subnodes = []
69        for i in range(nnodes):
70            if nodemap[i] == 1:
71                subnodes.append([i,nodes[i][0],nodes[i][1]])
72        node_list.append(subnodes)
73
74        # move to the next processor
75
76        tlower = tupper
77
78    # put the results in a dictionary
79
80    submesh["full_nodes"] = node_list
81    submesh["full_triangles"] = triangle_list
82    submesh["full_boundary"] = boundary_list
83
84    # clean up before exiting
85
86    del (nodemap)
87
88    return submesh
89
90
91#########################################################
92#
93# Build the ghost layer of triangles
94#
95#  *) Given the triangle subpartion for the processor
96# build a ghost layer of triangles. The ghost layer
97# consists of two layers of neighbouring triangles.
98#
99#  *) The vertices in the ghost triangles must also
100# be added to the node list for the current processor
101#
102#  *) The boundary edges for the ghost triangles are
103# ignored.
104#
105# -------------------------------------------------------
106#
107#  *) The extra triangles and nodes are returned.
108#
109#  *)  The node information consists of
110# [global_id, x_coord, y_coord].
111#
112#  *) The triangle information consists of
113# [triangle number, t], where t = [v1, v2, v3].
114#
115#########################################################
116
117def ghost_layer(submesh, mesh, p, tupper, tlower):
118
119    # find the first layer of boundary triangles
120
121    trianglemap = map(lambda n: 0, mesh.triangles)
122    for t in range(tlower, tupper):
123        n = mesh.neighbours[t, 0]
124        if n > 0:
125            if n < tlower or n >= tupper:
126                trianglemap[n] = 1
127        n = mesh.neighbours[t, 1]
128        if n > 0:
129            if n < tlower or n >= tupper:
130                trianglemap[n] = 1
131        n = mesh.neighbours[t, 2]
132        if n > 0:
133            if n < tlower or n >= tupper:
134                trianglemap[n] = 1
135
136    # find the second layer of boundary triangles
137
138    for t in range(len(trianglemap)):
139        if trianglemap[t]==1:
140            n = mesh.neighbours[t, 0]
141            if n > 0:
142                if (n < tlower or n >= tupper) and trianglemap[n] == 0:
143                    trianglemap[n] = 1
144            n = mesh.neighbours[t, 1]
145            if n > 0:
146                if (n < tlower or n >= tupper) and trianglemap[n] == 0:
147                    trianglemap[n] = 1
148            n = mesh.neighbours[t, 2]
149            if n > 0:
150                if (n < tlower or n >= tupper) and trianglemap[n] == 0:
151                    trianglemap[n] = 1
152
153    # build the triangle list and make note of the vertices
154
155    nodemap = map(lambda n: 0, mesh.coordinates)
156    fullnodes = submesh["full_nodes"][p]
157    subtriangles = []
158    for i in range(len(trianglemap)):
159        if trianglemap[i] == 1:
160            t = list(mesh.triangles[i])
161            nodemap[t[0]] = 1
162            nodemap[t[1]] = 1
163            nodemap[t[2]] = 1
164            subtriangles.append([i, t])
165
166    # keep a record of the triangle vertices, if they are not already there
167
168    subnodes = []
169    for n in fullnodes:
170        nodemap[n[0]] = 0
171    for i in range(len(nodemap)):
172        if nodemap[i] == 1:
173            node = list(mesh.coordinates[i])
174            subnodes.append([i, node[0], node[1]])
175
176    # clean up before exiting
177
178    del (nodemap)
179    del (trianglemap)
180
181    # return the triangles and vertices sitting on the boundary layer
182
183    return subnodes, subtriangles
184
185
186#########################################################
187#
188# The ghost triangles on the current processor will need
189# to get updated information from the neighbouring
190# processor containing the corresponding full triangles.
191#
192#  *) The tri_per_proc is used to determine which
193# processor contains the full node copy.
194#
195# -------------------------------------------------------
196#
197#  *) The ghost communication pattern consists of
198# [global node number, neighbour processor number].
199#
200#########################################################
201
202def ghost_commun_pattern(subtri, p, tri_per_proc):
203
204    # loop over the ghost triangles
205
206    ghost_commun = []
207    for t in subtri:
208        global_no = t[0]
209
210        # find which processor contains the full triangle
211
212        nproc = len(tri_per_proc)
213        neigh = nproc-1
214        sum = 0
215        for q in range(nproc-1):
216            if (global_no < sum+tri_per_proc[q]):
217                neigh = q
218                break
219            sum = sum+tri_per_proc[q]
220
221        # keep a copy of the neighbour processor number
222
223        ghost_commun.append([global_no, neigh])
224
225    return ghost_commun
226
227#########################################################
228#
229# The full triangles in this processor must communicate
230# updated information to neighbouring processor that
231# contain ghost triangles
232#
233#  *) The ghost communication pattern for all of the
234# processor must be built before calling this processor.
235#
236#  *) The full communication pattern is found by looping
237# through the ghost communication pattern for all of the
238# processors. Recall that this information is stored in
239# the form [global node number, neighbour processor number].
240# The full communication for the neighbour processor is
241# then updated.
242#
243# -------------------------------------------------------
244#
245#  *) The full communication pattern consists of
246# [global id, [p1, p2, ...]], where p1, p2 etc contain
247# a ghost node copy of the triangle global id.
248#
249#########################################################
250
251def full_commun_pattern(submesh, tri_per_proc):
252    tlower = 0
253    nproc = len(tri_per_proc)
254    full_commun = []
255
256    # loop over the processor
257
258    for p in range(nproc):
259
260        # loop over the full triangles in the current processor
261        # and build an empty dictionary
262
263        fcommun = {}
264        tupper = tri_per_proc[p]+tlower
265        for i in range(tlower, tupper):
266            fcommun[i] = []
267        full_commun.append(fcommun)
268        tlower = tupper
269
270    # loop over the processor again
271
272    for p in range(nproc):
273
274        # loop over the ghost triangles in the current processor,
275        # find which processor contains the corresponding full copy
276        # and make note that that processor must send updates to this
277        # processor
278
279        for g in submesh["ghost_commun"][p]:
280            neigh = g[1]
281            full_commun[neigh][g[0]].append(p)
282
283    return full_commun
284
285
286#########################################################
287#
288# Given the non-overlapping grid partition, an extra layer
289# of triangles are included to help with the computations.
290# The triangles in this extra layer are not updated by
291# the processor, their updated values must be sent by the
292# processor containing the original, full, copy of the
293# triangle. The communication pattern that controls these
294# updates must also be built.
295#
296#  *) See the documentation for ghost_layer,
297# ghost_commun_pattern and full_commun_pattern
298#
299# -------------------------------------------------------
300#
301#  *) The additional information is added to the submesh
302# dictionary. See the documentation for ghost_layer,
303# ghost_commun_pattern and full_commun_pattern
304#
305#  *) The ghost_triangles, ghost_nodes, ghost_commun and
306# full_commun is added to submesh
307#########################################################
308
309def submesh_ghost(submesh, mesh, triangles_per_proc):
310
311    nproc = len(triangles_per_proc)
312    tlower = 0
313    ghost_triangles = []
314    ghost_nodes = []
315    ghost_commun = []
316
317    # loop over processors
318
319    for p in range(nproc):
320
321        # find the full triangles in this processor
322
323        tupper = triangles_per_proc[p]+tlower
324
325        # build the ghost boundary layer
326
327        [subnodes, subtri] = ghost_layer(submesh, mesh, p, tupper, tlower)
328        ghost_triangles.append(subtri)
329        ghost_nodes.append(subnodes)
330
331        # build the communication pattern for the ghost nodes
332
333        gcommun = ghost_commun_pattern(subtri, p, triangles_per_proc)
334        ghost_commun.append(gcommun)
335
336        # move to the next processor
337
338        tlower = tupper
339
340    # record the ghost layer and communication pattern
341
342    submesh["ghost_nodes"] = ghost_nodes
343    submesh["ghost_triangles"] = ghost_triangles
344    submesh["ghost_commun"] = ghost_commun
345
346    # build the communication pattern for the full triangles
347
348    full_commun = full_commun_pattern(submesh, triangles_per_proc)
349    submesh["full_commun"] = full_commun
350
351    # return the submesh
352
353    return submesh
354
355def submesh_quantities(submesh, quantities, triangles_per_proc):
356   
357    nproc = len(triangles_per_proc)
358
359    lower = 0
360
361    submesh["full_quan"] = {}
362    submesh["ghost_quan"] = {}
363
364    for k in quantities:
365        submesh["full_quan"][k] = []
366        submesh["ghost_quan"][k] = []
367                   
368    for p in range(nproc):
369        upper =   lower+triangles_per_proc[p]
370
371        global_id = []
372        M = len(submesh["ghost_triangles"][p])
373        for j in range(M):
374            global_id.append(submesh["ghost_triangles"][p][j][0])
375
376        for k in quantities:
377            submesh["full_quan"][k].append(quantities[k][lower:upper])
378            submesh["ghost_quan"][k].append(zeros( (M,3) , Float))
379            for j in range(M):
380                submesh["ghost_quan"][k][p][j] = quantities[k][global_id[j]]
381
382        lower = upper
383
384    return submesh
385
386#########################################################
387#
388# Build the grid partition on the host.
389#
390#  *) See the documentation for submesh_ghost and
391# submesh_full
392#
393# -------------------------------------------------------
394#
395#  *) A dictionary containing the full_triangles,
396# full_nodes, full_boundary, ghost_triangles, ghost_nodes,
397# ghost_commun and full_commun is returned.
398#
399#########################################################
400
401def build_submesh(nodes, triangles, edges, quantities,
402                  triangles_per_proc):
403
404    # temporarily build the mesh to find the neighbouring
405    # triangles
406
407    mesh = Mesh(nodes, triangles)
408
409    # subdivide into non-overlapping partitions
410
411    submeshf = submesh_full(nodes, triangles, edges, triangles_per_proc)
412
413    # add any extra ghost boundary layer information
414
415    submeshg = submesh_ghost(submeshf, mesh, triangles_per_proc)
416
417    submesh = submesh_quantities(submeshg, quantities, triangles_per_proc)
418   
419    return submesh
420
421#########################################################
422#
423# Extract the submesh that will belong to the
424# "host processor" (i.e. processor zero)
425#
426#  *) See the documentation for build_submesh
427#
428# -------------------------------------------------------
429#
430#  *) A dictionary containing the full_triangles,
431# full_nodes, full_boundary, ghost_triangles, ghost_nodes,
432# ghost_commun and full_commun belonging to processor zero
433# are returned.
434#
435#########################################################
436def extract_hostmesh(submesh):
437
438    submesh_cell = {}
439    submesh_cell["full_nodes"] = submesh["full_nodes"][0]
440    submesh_cell["ghost_nodes"] = submesh["ghost_nodes"][0]
441    submesh_cell["full_triangles"] = submesh["full_triangles"][0]
442    submesh_cell["ghost_triangles"] = submesh["ghost_triangles"][0]
443    submesh_cell["full_boundary"] = submesh["full_boundary"][0]
444    submesh_cell["ghost_commun"] = submesh["ghost_commun"][0]
445    submesh_cell["full_commun"] = submesh["full_commun"][0]
446    submesh_cell["full_quan"] ={}
447    submesh_cell["ghost_quan"]={}
448    for k in submesh["full_quan"]:
449        submesh_cell["full_quan"][k] = submesh["full_quan"][k][0]
450        submesh_cell["ghost_quan"][k] = submesh["ghost_quan"][k][0]
451       
452    return submesh_cell
453
454
Note: See TracBrowser for help on using the repository browser.