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

Last change on this file since 8282 was 8282, checked in by steve, 12 years ago

Working on merging sww from paralle runs

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