source: trunk/anuga_core/anuga/parallel/parallel_shallow_water.py @ 9679

Last change on this file since 9679 was 9500, checked in by steve, 10 years ago

setup up to move anuga_parllel to anuga.parallel

File size: 8.9 KB
Line 
1"""Class Parallel_shallow_water_domain -
22D triangular domains for finite-volume computations of
3the shallow water equation, with extra structures to allow
4communication between other Parallel_domains and itself
5
6This module contains a specialisation of class Domain
7from module shallow_water.py
8
9Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
10Geoscience Australia, 2004-2005
11
12"""
13
14from anuga import Domain
15
16import parallel_generic_communications as generic_comms
17
18import anuga.utilities.parallel_abstraction as pypar
19
20#from anuga.abstract_2d_finite_volumes.neighbour_mesh import Mesh
21
22import numpy as num
23from os.path import join
24
25
26#Import matplotlib
27
28
29
30class Parallel_domain(Domain):
31
32    def __init__(self, coordinates, vertices,
33                 boundary=None,
34                 full_send_dict=None,
35                 ghost_recv_dict=None,
36                 number_of_full_nodes=None,
37                 number_of_full_triangles=None,
38                 geo_reference=None,
39                 processor = None,
40                 numproc = None,
41                 number_of_global_triangles=None, ## SR added this
42                 number_of_global_nodes= None, ## SR added this
43                 s2p_map=None,
44                 p2s_map=None, #jj added this
45                 tri_l2g = None, ## SR added this
46                 node_l2g = None, #): ## SR added this
47                 ghost_layer_width = 2): ## SR added this
48
49
50
51        #-----------------------------------------
52        # Sometimes we want to manually
53        # create instances of the parallel_domain
54        # otherwise ...
55        #----------------------------------------
56        if processor is None:
57            processor = pypar.rank()
58        if numproc is None:
59            numproc = pypar.size()
60
61        Domain.__init__(self,
62                        coordinates,
63                        vertices,
64                        boundary,
65                        full_send_dict=full_send_dict,
66                        ghost_recv_dict=ghost_recv_dict,
67                        processor=processor,
68                        numproc=numproc,
69                        number_of_full_nodes=number_of_full_nodes,
70                        number_of_full_triangles=number_of_full_triangles,
71                        geo_reference=geo_reference, #) #jj added this
72                        ghost_layer_width = ghost_layer_width)
73       
74
75        self.parallel = True
76
77        # PETE: Find the number of full nodes and full triangles, this is a temporary fix
78        # until the bug with get_number_of_full_[nodes|triangles]() is fixed.
79
80        if number_of_full_nodes is not None:
81            self.number_of_full_nodes_tmp = number_of_full_nodes
82        else:
83            self.number_of_full_nodes_tmp = self.get_number_of_nodes()
84
85        if number_of_full_triangles is not None:
86            self.number_of_full_triangles_tmp = number_of_full_triangles
87        else:
88            self.number_of_full_triangles_tmp = self.get_number_of_triangles()
89
90        generic_comms.setup_buffers(self)
91
92        self.global_name = 'domain'
93
94        self.number_of_global_triangles=number_of_global_triangles
95        self.number_of_global_nodes = number_of_global_nodes
96
97        self.s2p_map = s2p_map
98        self.p2s_map = p2s_map
99
100
101        self.s2p_map = None
102        self.p2s_map = None
103
104        self.tri_l2g = tri_l2g
105        self.node_l2g = node_l2g
106
107        self.ghost_counter = 0
108
109
110    def set_name(self, name):
111        """Assign name based on processor number
112        """
113
114        if name.endswith('.sww'):
115            name = name[:-4]
116
117        self.global_name = name
118
119        # Call parents method with processor number attached.
120        Domain.set_name(self, name + '_P%d_%d' %(self.numproc, self.processor))
121
122
123    def get_global_name(self):
124
125        return self.global_name
126
127
128    def update_timestep(self, yieldstep, finaltime):
129        """Calculate local timestep
130        """
131
132        generic_comms.communicate_flux_timestep(self, yieldstep, finaltime)
133
134        Domain.update_timestep(self, yieldstep, finaltime)
135
136
137
138    def update_ghosts(self):
139        """We must send the information from the full cells and
140        receive the information for the ghost cells
141        """
142           
143        generic_comms.communicate_ghosts_asynchronous(self)
144        #generic_comms.communicate_ghosts_blocking(self)
145
146    def apply_fractional_steps(self):
147
148        for operator in self.fractional_step_operators:
149            operator()
150
151        # PETE: Make sure that there are no deadlocks here
152
153        #self.update_ghosts()
154
155
156
157    def sww_merge(self, verbose=False, delete_old=False):
158
159        # make sure all the computations have finished
160
161        pypar.barrier()
162
163        # now on processor 0 pull all the separate sww files together
164        if self.processor == 0 and self.numproc > 1 and self.store :
165            import anuga.utilities.sww_merge as merge
166
167            global_name = join(self.get_datadir(),self.get_global_name())
168           
169            merge.sww_merge_parallel(global_name,self.numproc,verbose,delete_old)
170
171        # make sure all the merge completes on processor 0 before other
172        # processors complete (like when finalize is forgotten in main script)
173       
174        pypar.barrier()
175       
176    def write_time(self):
177
178        if self.processor == 0:
179            Domain.write_time(self)
180
181
182# =======================================================================
183# PETE: NEW METHODS FOR FOR PARALLEL STRUCTURES. Note that we assume the
184# first "number_of_full_[nodes|triangles]" are full [nodes|triangles]
185# For full triangles it is possible to enquire self.tri_full_flag == True
186# =======================================================================
187
188    def get_number_of_full_triangles(self, *args, **kwargs):
189        return self.number_of_full_triangles_tmp
190
191    def get_full_centroid_coordinates(self, *args, **kwargs):
192        C = self.mesh.get_centroid_coordinates(*args, **kwargs)
193        return C[:self.number_of_full_triangles_tmp, :]
194
195    def get_full_vertex_coordinates(self, *args, **kwargs):
196        V = self.mesh.get_vertex_coordinates(*args, **kwargs)
197        return V[:3*self.number_of_full_triangles_tmp,:]
198
199    def get_full_triangles(self, *args, **kwargs):
200        T = self.mesh.get_triangles(*args, **kwargs)
201        return T[:self.number_of_full_triangles_tmp,:]
202
203    def get_full_nodes(self, *args, **kwargs):
204        N = self.mesh.get_nodes(*args, **kwargs)
205        return N[:self.number_of_full_nodes_tmp,:]
206
207    def get_tri_map(self):
208        return self.tri_map
209
210    def get_inv_tri_map(self):
211        return self.inv_tri_map
212
213    '''
214    Outputs domain triangulation, full triangles are shown in green while ghost triangles are shown in blue.
215    The default filename is "domain.png"
216    '''
217    def dump_triangulation(self, filename="domain.png"):
218        # Get vertex coordinates, partition full and ghost triangles based on self.tri_full_flag
219
220        try:
221            import matplotlib
222            matplotlib.use('Agg')
223            import matplotlib.pyplot as plt
224            import matplotlib.tri as tri
225        except:
226            print "Couldn't import module from matplotlib, probably you need to update matplotlib"
227            raise
228
229        vertices = self.get_vertex_coordinates()
230        full_mask = num.repeat(self.tri_full_flag == 1, 3)
231        ghost_mask = num.repeat(self.tri_full_flag == 0, 3)
232       
233        myid = pypar.rank()
234        numprocs = pypar.size()
235
236        if myid == 0:
237
238            fig = plt.figure()
239            fx = {}
240            fy = {}
241            gx = {}
242            gy = {}
243
244            # Proc 0 gathers full and ghost nodes from self and other processors
245            fx[0] = vertices[full_mask,0]
246            fy[0] = vertices[full_mask,1]
247            gx[0] = vertices[ghost_mask,0]
248            gy[0] = vertices[ghost_mask,1]
249           
250            for i in range(1,numprocs):
251                fx[i] = pypar.receive(i)
252                fy[i] = pypar.receive(i)
253                gx[i] = pypar.receive(i)
254                gy[i] = pypar.receive(i)
255
256            # Plot full triangles
257            for i in range(0, numprocs):
258                n = int(len(fx[i])/3)
259                           
260                triang = num.array(range(0,3*n))
261                triang.shape = (n, 3)
262                plt.triplot(fx[i], fy[i], triang, 'g-', linewidth = 0.5)
263
264            # Plot ghost triangles
265            for i in range(0, numprocs):
266                n = int(len(gx[i])/3)
267                if n > 0:
268                    triang = num.array(range(0,3*n))
269                    triang.shape = (n, 3)
270                    plt.triplot(gx[i], gy[i], triang, 'b--', linewidth = 0.5)
271
272            # Save triangulation to location pointed by filename
273            plt.savefig(filename, dpi=600)
274
275        else:
276            # Proc 1..numprocs send full and ghost triangles to Proc 0
277            pypar.send(vertices[full_mask,0], 0)
278            pypar.send(vertices[full_mask,1], 0)
279            pypar.send(vertices[ghost_mask,0], 0)
280            pypar.send(vertices[ghost_mask,1], 0)
281           
282
Note: See TracBrowser for help on using the repository browser.