source: inundation/ga/storm_surge/parallel/parallel_advection.py @ 1426

Last change on this file since 1426 was 1426, checked in by steve, 19 years ago
File size: 14.1 KB
Line 
1import sys
2from os import sep
3sys.path.append('..'+sep+'pyvolution')
4
5"""Class Parallel_Domain -
62D triangular domains for finite-volume computations of
7the advection equation, with extra structures to allow
8communication between other Parallel_Domains and itself
9
10This module contains a specialisation of class Domain from module advection.py
11
12Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
13Geoscience Australia, 2004
14"""
15
16from advection import *
17Advection_Domain = Domain
18from Numeric import zeros, Float, Int, ones, allclose, array
19import pypar
20
21
22class Parallel_Domain(Advection_Domain):
23
24    def __init__(self, coordinates, vertices, boundary = None,
25                 full_send_dict = None, ghost_recv_dict = None,
26                 velocity = None):
27
28        self.processor = pypar.rank()
29        self.numproc   = pypar.size()
30        #print 'Processor %d'%self.processor
31        #velocity = [(self.processor+1),0.0]
32
33        #print 'velocity',velocity
34
35        Advection_Domain.__init__(self, coordinates, vertices, boundary, velocity)
36
37        N = self.number_of_elements
38
39        self.processor = pypar.rank()
40        self.numproc   = pypar.size()
41
42        self.full_send_dict  = full_send_dict
43        self.ghost_recv_dict = ghost_recv_dict
44
45        #print self.full_send_dict
46        #print self.ghost_recv_dict
47
48    def check_integrity(self):
49        Advection_Domain.check_integrity(self)
50
51        msg = 'Will need to check global and local numbering'
52        assert self.conserved_quantities[0] == 'stage', msg
53
54
55
56    def update_timestep(self, yieldstep, finaltime):
57
58        # Calculate local timestep
59        Advection_Domain.update_timestep(self, yieldstep, finaltime)
60
61        # For some reason it looks like pypar only reduces numeric arrays
62        # hence we need to create some dummy arrays for communication
63        ltimestep = ones( 1, Float )
64        ltimestep[0] = self.timestep
65
66        gtimestep = zeros( 1, Float) # Buffer for results
67
68        pypar.raw_reduce(ltimestep, gtimestep, pypar.MIN, 0)
69        pypar.broadcast(gtimestep,0)
70        #pypar.Barrier()
71
72        self.timestep = gtimestep[0]
73
74
75
76    def update_ghosts(self):
77
78        # We must send the information from the full cells and
79        # receive the information for the ghost cells
80        # We have a dictionary of lists with ghosts expecting updates from
81        # the separate processors
82
83        stage_cv = self.quantities['stage'].centroid_values
84
85        # update of non-local ghost cells
86        for iproc in range(self.numproc):
87
88            if iproc == self.processor:
89                #Send data from iproc processor to other processors
90                for send_proc in self.full_send_dict:
91                    if send_proc != iproc:
92                        Idf  = self.full_send_dict[send_proc][0]
93                        Xout = self.full_send_dict[send_proc][1]
94                        for i, _ in enumerate(Xout):
95                            Xout[i] = stage_cv[Idf[i]]
96
97                        pypar.send(Xout,send_proc)
98                        print 'Processor %d Sending to Processor %d'%(self.processor,send_proc)
99            else:
100                #Receive data from the iproc processor
101                if  self.ghost_recv_dict.has_key(iproc):
102                    Idg = self.ghost_recv_dict[iproc][0]
103                    X   = self.ghost_recv_dict[iproc][1]
104
105                    X = pypar.receive(iproc,X)
106                    print 'Processor %d receiving from Processor %d'%(self.processor,iproc)
107                    for i, _ in enumerate(X):
108                        stage_cv[Idg[i]] = X[i]
109            pypar.barrier()
110
111        #local update of ghost cells
112        iproc = self.processor
113        if self.full_send_dict.has_key(iproc):
114            Idf  = self.full_send_dict[iproc][0]
115            #print Idf
116            Idg  = self.ghost_recv_dict[iproc][0]
117            #print Idg
118            for i, _ in enumerate(Idf):
119                #print i,Idg[i],Idf[i]
120                stage_cv[Idg[i]] = stage_cv[Idf[i]]
121
122
123#        if self.ghosts is not None:
124#            stage_cv = self.quantities['stage'].centroid_values
125#            for triangle in self.ghosts:
126#                stage_cv[triangle] = stage_cv[self.ghosts[triangle]]
127
128
129    def write_time(self):
130        if self.min_timestep == self.max_timestep:
131            print 'Processor %d, Time = %.4f, delta t = %.8f, steps=%d (%d)'\
132                  %(self.processor, self.time, self.min_timestep, self.number_of_steps,
133                    self.number_of_first_order_steps)
134        elif self.min_timestep > self.max_timestep:
135            print 'Processor %d, Time = %.4f, steps=%d (%d)'\
136                  %(self.processor, self.time, self.number_of_steps,
137                    self.number_of_first_order_steps)
138        else:
139            print 'Processor %d, Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
140                  %(self.processor, self.time, self.min_timestep,
141                    self.max_timestep, self.number_of_steps,
142                    self.number_of_first_order_steps)
143
144
145
146    def evolve(self, yieldstep = None, finaltime = None):
147        """Specialisation of basic evolve method from parent class
148        """
149
150        #Initialise real time viz if requested
151        if self.time == 0.0:
152            pass
153
154        #Call basic machinery from parent class
155        for t in Advection_Domain.evolve(self, yieldstep, finaltime):
156
157            #Pass control on to outer loop for more specific actions
158            yield(t)
159
160
161
162
163def parallel_rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
164
165
166    """Setup a rectangular grid of triangles
167    with m+1 by n+1 grid points
168    and side lengths len1, len2. If side lengths are omitted
169    the mesh defaults to the unit square, divided between all the
170    processors
171
172    len1: x direction (left to right)
173    len2: y direction (bottom to top)
174
175    """
176
177    from config import epsilon
178    from Numeric import zeros, Float, Int
179
180    processor = pypar.rank()
181    numproc   = pypar.size()
182
183
184
185    delta1 = float(len1)/m
186    delta2 = float(len2)/n
187
188    #Calculate number of points
189    Np = (m+1)*(n+1)
190
191    class VIndex:
192
193        def __init__(self, n,m):
194            self.n = n
195            self.m = m
196
197        def __call__(self, i,j):
198            return j+i*(self.n+1)
199
200    class EIndex:
201
202        def __init__(self, n,m):
203            self.n = n
204            self.m = m
205
206        def __call__(self, i,j):
207            return 2*(j+i*self.n)
208
209
210    I = VIndex(n,m)
211    E = EIndex(n,m)
212
213    points = zeros( (Np,2), Float)
214
215    for i in range(m+1):
216        for j in range(n+1):
217
218            points[I(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
219
220    #Construct 2 triangles per rectangular element and assign tags to boundary
221    #Calculate number of triangles
222    Nt = 2*m*n
223
224
225    elements = zeros( (Nt,3), Int)
226    boundary = {}
227    Idgl = []
228    Xgl  = []
229    Idfl = []
230    Xfl  = []
231    Idgr = []
232    Xgr  = []
233    Idfr = []
234    Xfr  = []
235
236    full_send_dict = {}
237    ghost_recv_dict = {}
238    nt = -1
239    for i in range(m):
240        for j in range(n):
241
242            i1 = I(i,j+1)
243            i2 = I(i,j)
244            i3 = I(i+1,j+1)
245            i4 = I(i+1,j)
246
247            #Lower Element
248            nt = E(i,j)
249            if i == m-1:
250                #print 'nt =',nt
251                Idgr.append(nt)
252                Idfr.append(E(1,j))
253            if i == 0:
254                Idgl.append(nt)
255                Idfl.append(E(m-2,j))
256
257            if i == m-1:
258                boundary[nt, 2] = 'right'
259            if j == 0:
260                boundary[nt, 1] = 'bottom'
261            elements[nt,:] = [i4,i3,i2]
262
263            #Upper Element
264            nt = E(i,j)+1
265            if i == m-1:
266                Idgr.append(nt)
267                Idfr.append(E(1,j)+1)
268            if i == 0:
269                Idgl.append(nt)
270                Idfl.append(E(m-2,j)+1)
271
272            if i == 0:
273                boundary[nt, 2] = 'left'
274            if j == n-1:
275                boundary[nt, 1] = 'top'
276            elements[nt,:] = [i1,i2,i3]
277
278    Idfl = array(Idfl,Int)
279    Idgl = array(Idgl,Int)
280    Xfl  = zeros(Idfl.shape,Float)
281    Xgl  = zeros(Idgl.shape,Float)
282
283    Idfr = array(Idfr,Int)
284    Idgr = array(Idgr,Int)
285    Xfr  = zeros(Idfr.shape,Float)
286    Xgr  = zeros(Idgr.shape,Float)
287
288    #print Idf
289    #print Idg
290    full_send_dict[(processor-1)%numproc]  = [Idfl, Xfl]
291    ghost_recv_dict[(processor-1)%numproc] = [Idgl, Xgl]
292    full_send_dict[(processor+1)%numproc]  = [Idfr, Xfr]
293    ghost_recv_dict[(processor+1)%numproc] = [Idgr, Xgr]
294
295    return  points, elements, boundary, full_send_dict, ghost_recv_dict
296
297
298
299def rectangular_periodic(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
300
301
302    """Setup a rectangular grid of triangles
303    with m+1 by n+1 grid points
304    and side lengths len1, len2. If side lengths are omitted
305    the mesh defaults to the unit square.
306
307    len1: x direction (left to right)
308    len2: y direction (bottom to top)
309
310    Return to lists: points and elements suitable for creating a Mesh or
311    FVMesh object, e.g. Mesh(points, elements)
312    """
313
314    from config import epsilon
315    from Numeric import zeros, Float, Int
316
317    delta1 = float(len1)/m
318    delta2 = float(len2)/n
319
320    #Calculate number of points
321    Np = (m+1)*(n+1)
322
323    class VIndex:
324
325        def __init__(self, n,m):
326            self.n = n
327            self.m = m
328
329        def __call__(self, i,j):
330            return j+i*(self.n+1)
331
332    class EIndex:
333
334        def __init__(self, n,m):
335            self.n = n
336            self.m = m
337
338        def __call__(self, i,j):
339            return 2*(j+i*self.n)
340
341
342    I = VIndex(n,m)
343    E = EIndex(n,m)
344
345    points = zeros( (Np,2), Float)
346
347    for i in range(m+1):
348        for j in range(n+1):
349
350            points[I(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
351
352    #Construct 2 triangles per rectangular element and assign tags to boundary
353    #Calculate number of triangles
354    Nt = 2*m*n
355
356
357    elements = zeros( (Nt,3), Int)
358    boundary = {}
359    ghosts = {}
360    nt = -1
361    for i in range(m):
362        for j in range(n):
363
364            i1 = I(i,j+1)
365            i2 = I(i,j)
366            i3 = I(i+1,j+1)
367            i4 = I(i+1,j)
368
369            #Lower Element
370            nt = E(i,j)
371            if i == m-1:
372                ghosts[nt] = E(1,j)
373            if i == 0:
374                ghosts[nt] = E(m-2,j)
375
376            if j == n-1:
377                ghosts[nt] = E(i,1)
378
379            if j == 0:
380                ghosts[nt] = E(i,n-2)
381
382            if i == m-1:
383                boundary[nt, 2] = 'right'
384            if j == 0:
385                boundary[nt, 1] = 'bottom'
386            elements[nt,:] = [i4,i3,i2]
387
388            #Upper Element
389            nt = E(i,j)+1
390            if i == m-1:
391                ghosts[nt] = E(1,j)+1
392            if i == 0:
393                ghosts[nt] = E(m-2,j)+1
394
395            if j == n-1:
396                ghosts[nt] = E(i,1)+1
397
398            if j == 0:
399                ghosts[nt] = E(i,n-2)+1
400
401            if i == 0:
402                boundary[nt, 2] = 'left'
403            if j == n-1:
404                boundary[nt, 1] = 'top'
405            elements[nt,:] = [i1,i2,i3]
406
407    #bottom left
408    nt = E(0,0)
409    nf = E(m-2,n-2)
410    ghosts[nt]   = nf
411    ghosts[nt+1] = nf+1
412
413    #bottom right
414    nt = E(m-1,0)
415    nf = E(1,n-2)
416    ghosts[nt]   = nf
417    ghosts[nt+1] = nf+1
418
419    #top left
420    nt = E(0,n-1)
421    nf = E(m-2,1)
422    ghosts[nt]   = nf
423    ghosts[nt+1] = nf+1
424
425    #top right
426    nt = E(m-1,n-1)
427    nf = E(1,1)
428    ghosts[nt]   = nf
429    ghosts[nt+1] = nf+1
430
431    return points, elements, boundary, ghosts
432
433def rectangular_periodic_lr(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
434
435
436    """Setup a rectangular grid of triangles
437    with m+1 by n+1 grid points
438    and side lengths len1, len2. If side lengths are omitted
439    the mesh defaults to the unit square.
440
441    len1: x direction (left to right)
442    len2: y direction (bottom to top)
443
444    Return to lists: points and elements suitable for creating a Mesh or
445    Domain object, e.g. Mesh(points, elements)
446    """
447
448    from config import epsilon
449    from Numeric import zeros, Float, Int
450
451    delta1 = float(len1)/m
452    delta2 = float(len2)/n
453
454    #Calculate number of points
455    Np = (m+1)*(n+1)
456
457    class VIndex:
458
459        def __init__(self, n,m):
460            self.n = n
461            self.m = m
462
463        def __call__(self, i,j):
464            return j+i*(self.n+1)
465
466    class EIndex:
467
468        def __init__(self, n,m):
469            self.n = n
470            self.m = m
471
472        def __call__(self, i,j):
473            return 2*(j+i*self.n)
474
475
476    I = VIndex(n,m)
477    E = EIndex(n,m)
478
479    points = zeros( (Np,2), Float)
480
481    for i in range(m+1):
482        for j in range(n+1):
483
484            points[I(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
485
486    #Construct 2 triangles per rectangular element and assign tags to boundary
487    #Calculate number of triangles
488    Nt = 2*m*n
489
490
491    elements = zeros( (Nt,3), Int)
492    boundary = {}
493    ghosts = {}
494    nt = -1
495    for i in range(m):
496        for j in range(n):
497
498            i1 = I(i,j+1)
499            i2 = I(i,j)
500            i3 = I(i+1,j+1)
501            i4 = I(i+1,j)
502
503            #Lower Element
504            nt = E(i,j)
505            if i == m-1:
506                ghosts[nt] = E(1,j)
507            if i == 0:
508                ghosts[nt] = E(m-2,j)
509
510            if i == m-1:
511                boundary[nt, 2] = 'right'
512            if j == 0:
513                boundary[nt, 1] = 'bottom'
514            elements[nt,:] = [i4,i3,i2]
515
516            #Upper Element
517            nt = E(i,j)+1
518            if i == m-1:
519                ghosts[nt] = E(1,j)+1
520            if i == 0:
521                ghosts[nt] = E(m-2,j)+1
522
523            if i == 0:
524                boundary[nt, 2] = 'left'
525            if j == n-1:
526                boundary[nt, 1] = 'top'
527            elements[nt,:] = [i1,i2,i3]
528
529
530    return points, elements, boundary, ghosts
Note: See TracBrowser for help on using the repository browser.