source: trunk/anuga_core/source/anuga_parallel/parallel_api.py @ 8497

Last change on this file since 8497 was 8496, checked in by steve, 13 years ago

Some problems with dry regioons causing wierd results for
run_parallel_sw_merimbula.

File size: 9.9 KB
Line 
1"""Trying to lump parallel stuff into simpler interface
2
3
4"""
5
6
7
8# The abstract Python-MPI interface
9from anuga_parallel.parallel_abstraction import size, rank, get_processor_name
10from anuga_parallel.parallel_abstraction import finalize, send, receive
11from anuga_parallel.parallel_abstraction import pypar_available, barrier
12
13
14# ANUGA parallel engine (only load if pypar can)
15if pypar_available:
16    from anuga_parallel.distribute_mesh  import send_submesh
17    from anuga_parallel.distribute_mesh  import rec_submesh
18    from anuga_parallel.distribute_mesh  import extract_hostmesh
19
20    # Mesh partitioning using Metis
21    from anuga_parallel.distribute_mesh import build_submesh
22    from anuga_parallel.distribute_mesh import pmesh_divide_metis_with_map
23
24    from anuga_parallel.parallel_shallow_water import Parallel_domain
25
26#------------------------------------------------------------------------------
27# Read in processor information
28#------------------------------------------------------------------------------
29
30numprocs = size()
31myid = rank()
32processor_name = get_processor_name()
33#print 'I am processor %d of %d on node %s' %(myid, numprocs, processor_name)
34
35
36
37
38def distribute(domain, verbose=False, debug=False):
39    """ Distribute the domain to all processes
40    """
41
42
43    if debug:
44        verbose = True
45       
46    barrier()
47
48    # FIXME: Dummy assignment (until boundaries are refactored to
49    # be independent of domains until they are applied)
50    if myid == 0:
51        bdmap = {}
52        for tag in domain.get_boundary_tags():
53            bdmap[tag] = None
54   
55   
56        domain.set_boundary(bdmap)
57
58
59
60
61    if not pypar_available: return domain # Bypass
62
63    # For some obscure reason this communication must happen prior to
64    # the more complex mesh distribution - Oh Well!
65    if myid == 0:
66        domain_name = domain.get_name()
67        domain_dir = domain.get_datadir()
68        domain_store = domain.get_store()
69        georef = domain.geo_reference
70        number_of_global_triangles = domain.number_of_triangles
71        number_of_global_nodes = domain.number_of_nodes
72       
73        # FIXME - what other attributes need to be transferred?
74
75        for p in range(1, numprocs):
76            send((domain_name, domain_dir, domain_store, georef, \
77                  number_of_global_triangles, number_of_global_nodes), p)
78    else:
79        if verbose: print 'P%d: Receiving domain attributes' %(myid)
80
81        domain_name, domain_dir, domain_store, georef, \
82                  number_of_global_triangles, number_of_global_nodes = receive(0)
83
84
85
86    # Distribute boundary conditions
87    # FIXME: This cannot handle e.g. Time_boundaries due to
88    # difficulties pickling functions
89    if myid == 0:
90        boundary_map = domain.boundary_map
91        for p in range(1, numprocs):
92            send(boundary_map, p)
93    else:
94        if verbose: print 'P%d: Receiving boundary map' %(myid)       
95
96        boundary_map = receive(0)
97       
98
99
100
101    if myid == 0:
102        # Partition and distribute mesh.
103        # Structures returned is in the
104        # correct form for the ANUGA data structure
105
106
107        points, vertices, boundary, quantities,\
108                ghost_recv_dict, full_send_dict,\
109                number_of_full_nodes, number_of_full_triangles,\
110                s2p_map, p2s_map, tri_map, node_map =\
111                distribute_mesh(domain, verbose=verbose, debug=debug)
112
113
114
115
116           
117        # Extract l2g maps
118        tri_l2g  = extract_l2g_map(tri_map)
119        node_l2g = extract_l2g_map(node_map)
120
121        if debug:
122            print 'P%d' %myid
123            print 'tri_map ',tri_map
124            print 'node_map',node_map
125            print 'tri_l2g', tri_l2g
126            print 'node_l2g', node_l2g
127            print 's2p_map', s2p_map
128            print 'p2s_map', p2s_map
129
130        # Send serial to parallel (s2p) and parallel to serial (p2s) triangle mapping to proc 1 .. numprocs
131        for p in range(1, numprocs):
132            send(s2p_map, p)
133            send(p2s_map, p)
134
135        if verbose: print 'Communication done'
136       
137    else:
138        # Read in the mesh partition that belongs to this
139        # processor
140        if verbose: print 'P%d: Receiving submeshes' %(myid)               
141        points, vertices, boundary, quantities,\
142                ghost_recv_dict, full_send_dict,\
143                number_of_full_nodes, number_of_full_triangles, \
144                tri_map, node_map =\
145                rec_submesh(0, verbose)
146
147
148
149        # Extract l2g maps
150        tri_l2g  = extract_l2g_map(tri_map)
151        node_l2g = extract_l2g_map(node_map)
152       
153        # Recieve serial to parallel (s2p) and parallel to serial (p2s) triangle mapping
154        s2p_map = receive(0)
155        p2s_map = receive(0)
156
157
158    #------------------------------------------------------------------------
159    # Build the domain for this processor using partion structures
160    #------------------------------------------------------------------------
161
162    if verbose: print 'myid = %g, no_full_nodes = %g, no_full_triangles = %g' % (myid, number_of_full_nodes, number_of_full_triangles)
163
164   
165    domain = Parallel_domain(points, vertices, boundary,
166                             full_send_dict=full_send_dict,
167                             ghost_recv_dict=ghost_recv_dict,
168                             number_of_full_nodes=number_of_full_nodes,
169                             number_of_full_triangles=number_of_full_triangles,
170                             geo_reference=georef,
171                             number_of_global_triangles = number_of_global_triangles,
172                             number_of_global_nodes = number_of_global_nodes,
173                             s2p_map = s2p_map,
174                             p2s_map = p2s_map, ## jj added this
175                             tri_l2g = tri_l2g, ## SR added this
176                             node_l2g = node_l2g)
177
178    #------------------------------------------------------------------------
179    # Transfer initial conditions to each subdomain
180    #------------------------------------------------------------------------
181    for q in quantities:
182        domain.set_quantity(q, quantities[q]) 
183
184
185    #------------------------------------------------------------------------
186    # Transfer boundary conditions to each subdomain
187    #------------------------------------------------------------------------
188    boundary_map['ghost'] = None  # Add binding to ghost boundary
189    domain.set_boundary(boundary_map)
190
191
192    #------------------------------------------------------------------------
193    # Transfer other attributes to each subdomain
194    #------------------------------------------------------------------------
195    domain.set_name(domain_name)
196    domain.set_datadir(domain_dir)
197    domain.set_store(domain_store)
198    domain.geo_reference = georef   
199
200    #------------------------------------------------------------------------
201    # Return parallel domain to all nodes
202    #------------------------------------------------------------------------
203    return domain   
204
205
206
207
208
209
210def distribute_mesh(domain, verbose=False, debug=False):
211
212
213    if debug:
214        verbose = True
215
216    numprocs = size()
217
218   
219    # Subdivide the mesh
220    if verbose: print 'Subdivide mesh'
221    nodes, triangles, boundary, triangles_per_proc, quantities, \
222           s2p_map, p2s_map = \
223           pmesh_divide_metis_with_map(domain, numprocs)
224
225    #PETE: s2p_map (maps serial domain triangles to parallel domain triangles)
226    #      sp2_map (maps parallel domain triangles to domain triangles)
227
228
229    # Build the mesh that should be assigned to each processor,
230    # this includes ghost nodes and the communication pattern
231    if verbose: print 'Build submeshes'   
232    submesh = build_submesh(nodes, triangles, boundary,\
233                            quantities, triangles_per_proc)
234
235    if verbose:
236        for p in range(numprocs):
237            N = len(submesh['ghost_nodes'][p])               
238            M = len(submesh['ghost_triangles'][p])
239            print 'There are %d ghost nodes and %d ghost triangles on proc %d'\
240                  %(N, M, p)
241
242    #if debug:
243    #    from pprint import pprint
244    #    pprint(submesh)
245
246
247    # Send the mesh partition to the appropriate processor
248    if verbose: print 'Distribute submeshes'       
249    for p in range(1, numprocs):
250      send_submesh(submesh, triangles_per_proc, p, verbose)
251
252    # Build the local mesh for processor 0
253    points, vertices, boundary, quantities, \
254            ghost_recv_dict, full_send_dict, tri_map, node_map =\
255              extract_hostmesh(submesh, triangles_per_proc)
256
257    # Keep track of the number full nodes and triangles.
258    # This is useful later if one needs access to a ghost-free domain
259    # Here, we do it for process 0. The others are done in rec_submesh.
260    number_of_full_nodes = len(submesh['full_nodes'][0])
261    number_of_full_triangles = len(submesh['full_triangles'][0])
262       
263    #print
264    #for p in range(numprocs):
265    #    print 'Process %d:' %(p)
266    #
267    #    print 'full_triangles:'
268    #    print submesh['full_triangles'][p]
269    #
270    #    print 'full_nodes:'
271    #    print submesh['full_nodes'][p]
272    #
273    #    print 'ghost_triangles:'
274    #    print submesh['ghost_triangles'][p]#
275    #
276    #    print 'ghost_nodes:'
277    #   print submesh['ghost_nodes'][p]                               
278    #    print
279    #
280    #print 'Receive dict'
281    #print ghost_recv_dict
282    #
283    #print 'Send dict'
284    #print full_send_dict       
285
286
287    # Return structures necessary for building the parallel domain
288    return points, vertices, boundary, quantities,\
289           ghost_recv_dict, full_send_dict,\
290           number_of_full_nodes, number_of_full_triangles, \
291           s2p_map, p2s_map, tri_map, node_map
292   
293
294
295def extract_l2g_map(map):
296    # Extract l2g data  from corresponding map
297    # Maps
298
299    import numpy as num
300   
301    b = num.arange(len(map))
302
303    l_ids = num.extract(map>-1,map)
304    g_ids = num.extract(map>-1,b)
305
306#    print len(g_ids)
307#    print len(l_ids)
308#    print l_ids
309
310    l2g = num.zeros_like(g_ids)
311    l2g[l_ids] = g_ids
312
313    return l2g
314
Note: See TracBrowser for help on using the repository browser.