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

Last change on this file since 1460 was 1460, checked in by matthew, 20 years ago

resolved conflict after play around on 19/05/05

File size: 14.7 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        from weave import converters
84
85        stage_cv = self.quantities['stage'].centroid_values
86
87        # update of non-local ghost cells
88        for iproc in range(self.numproc):
89
90            if iproc == self.processor:
91                #Send data from iproc processor to other processors
92                for send_proc in self.full_send_dict:
93                    if send_proc != iproc:
94                        Idf  = self.full_send_dict[send_proc][0]
95                        Xout = self.full_send_dict[send_proc][1]
96                        N = len(Xout)
97
98                        """
99                        # Original python Code
100                        for i in range(N):
101                            Xout[i] = stage_cv[Idf[i]]
102                        """
103                        code1 = """
104                        for (int i=0; i<N ; i++){
105                            Xout(i) = stage_cv(Idf(i));
106                        }
107                        """
108                        weave.inline(code1, ['stage_cv','Idf','Xout','N'],
109                                     type_converters = converters.blitz, compiler='gcc');
110
111                        pypar.send(Xout,send_proc)
112                        #print 'Processor %d Sending to Processor %d'%(self.processor,send_proc)
113            else:
114                #Receive data from the iproc processor
115                if  self.ghost_recv_dict.has_key(iproc):
116                    Idg = self.ghost_recv_dict[iproc][0]
117                    X   = self.ghost_recv_dict[iproc][1]
118
119                    X = pypar.receive(iproc,X)
120                    N = len(X)
121                    #print 'Processor %d receiving from Processor %d'%(self.processor,iproc)
122                    for i in range(N):
123                        stage_cv[Idg[i]] = X[i]
124            pypar.barrier()
125
126        #local update of ghost cells
127        iproc = self.processor
128        if self.full_send_dict.has_key(iproc):
129            Idf  = self.full_send_dict[iproc][0]
130            #print Idf
131            Idg  = self.ghost_recv_dict[iproc][0]
132            N = len(Idg)
133            #print Idg
134            for i in range(N):
135                #print i,Idg[i],Idf[i]
136                stage_cv[Idg[i]] = stage_cv[Idf[i]]
137
138
139#        if self.ghosts is not None:
140#            stage_cv = self.quantities['stage'].centroid_values
141#            for triangle in self.ghosts:
142#                stage_cv[triangle] = stage_cv[self.ghosts[triangle]]
143
144
145    def write_time(self):
146        if self.min_timestep == self.max_timestep:
147            print 'Processor %d, Time = %.4f, delta t = %.8f, steps=%d (%d)'\
148                  %(self.processor, self.time, self.min_timestep, self.number_of_steps,
149                    self.number_of_first_order_steps)
150        elif self.min_timestep > self.max_timestep:
151            print 'Processor %d, Time = %.4f, steps=%d (%d)'\
152                  %(self.processor, self.time, self.number_of_steps,
153                    self.number_of_first_order_steps)
154        else:
155            print 'Processor %d, Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
156                  %(self.processor, self.time, self.min_timestep,
157                    self.max_timestep, self.number_of_steps,
158                    self.number_of_first_order_steps)
159
160
161
162    def evolve(self, yieldstep = None, finaltime = None):
163        """Specialisation of basic evolve method from parent class
164        """
165
166        #Initialise real time viz if requested
167        if self.time == 0.0:
168            pass
169
170        #Call basic machinery from parent class
171        for t in Advection_Domain.evolve(self, yieldstep, finaltime):
172
173            #Pass control on to outer loop for more specific actions
174            yield(t)
175
176
177
178
179def parallel_rectangular(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
180
181
182    """Setup a rectangular grid of triangles
183    with m+1 by n+1 grid points
184    and side lengths len1, len2. If side lengths are omitted
185    the mesh defaults to the unit square, divided between all the
186    processors
187
188    len1: x direction (left to right)
189    len2: y direction (bottom to top)
190    """
191
192    from config import epsilon
193    from Numeric import zeros, Float, Int
194
195    processor = pypar.rank()
196    numproc   = pypar.size()
197
198
199
200    delta1 = float(len1)/m
201    delta2 = float(len2)/n
202
203    #Calculate number of points
204    Np = (m+1)*(n+1)
205
206    class VIndex:
207
208        def __init__(self, n,m):
209            self.n = n
210            self.m = m
211
212        def __call__(self, i,j):
213            return j+i*(self.n+1)
214
215    class EIndex:
216
217        def __init__(self, n,m):
218            self.n = n
219            self.m = m
220
221        def __call__(self, i,j):
222            return 2*(j+i*self.n)
223
224
225    I = VIndex(n,m)
226    E = EIndex(n,m)
227
228    points = zeros( (Np,2), Float)
229
230    for i in range(m+1):
231        for j in range(n+1):
232
233            points[I(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
234
235    #Construct 2 triangles per rectangular element and assign tags to boundary
236    #Calculate number of triangles
237    Nt = 2*m*n
238
239
240    elements = zeros( (Nt,3), Int)
241    boundary = {}
242    Idgl = []
243    Xgl  = []
244    Idfl = []
245    Xfl  = []
246    Idgr = []
247    Xgr  = []
248    Idfr = []
249    Xfr  = []
250
251    full_send_dict = {}
252    ghost_recv_dict = {}
253    nt = -1
254    for i in range(m):
255        for j in range(n):
256
257            i1 = I(i,j+1)
258            i2 = I(i,j)
259            i3 = I(i+1,j+1)
260            i4 = I(i+1,j)
261
262            #Lower Element
263            nt = E(i,j)
264            if i == m-1:
265                #print 'nt =',nt
266                Idgr.append(nt)
267                Idfr.append(E(1,j))
268            if i == 0:
269                Idgl.append(nt)
270                Idfl.append(E(m-2,j))
271
272            if i == m-1:
273                boundary[nt, 2] = 'right'
274            if j == 0:
275                boundary[nt, 1] = 'bottom'
276            elements[nt,:] = [i4,i3,i2]
277
278            #Upper Element
279            nt = E(i,j)+1
280            if i == m-1:
281                Idgr.append(nt)
282                Idfr.append(E(1,j)+1)
283            if i == 0:
284                Idgl.append(nt)
285                Idfl.append(E(m-2,j)+1)
286
287            if i == 0:
288                boundary[nt, 2] = 'left'
289            if j == n-1:
290                boundary[nt, 1] = 'top'
291            elements[nt,:] = [i1,i2,i3]
292
293    Idfl = array(Idfl,Int)
294    Idgl = array(Idgl,Int)
295    Xfl  = zeros(Idfl.shape,Float)
296    Xgl  = zeros(Idgl.shape,Float)
297
298    Idfr = array(Idfr,Int)
299    Idgr = array(Idgr,Int)
300    Xfr  = zeros(Idfr.shape,Float)
301    Xgr  = zeros(Idgr.shape,Float)
302
303    #print Idf
304    #print Idg
305    full_send_dict[(processor-1)%numproc]  = [Idfl, Xfl]
306    ghost_recv_dict[(processor-1)%numproc] = [Idgl, Xgl]
307    full_send_dict[(processor+1)%numproc]  = [Idfr, Xfr]
308    ghost_recv_dict[(processor+1)%numproc] = [Idgr, Xgr]
309
310    return  points, elements, boundary, full_send_dict, ghost_recv_dict
311
312
313
314def rectangular_periodic(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
315
316
317    """Setup a rectangular grid of triangles
318    with m+1 by n+1 grid points
319    and side lengths len1, len2. If side lengths are omitted
320    the mesh defaults to the unit square.
321
322    len1: x direction (left to right)
323    len2: y direction (bottom to top)
324
325    Return to lists: points and elements suitable for creating a Mesh or
326    FVMesh object, e.g. Mesh(points, elements)
327    """
328
329    from config import epsilon
330    from Numeric import zeros, Float, Int
331
332    delta1 = float(len1)/m
333    delta2 = float(len2)/n
334
335    #Calculate number of points
336    Np = (m+1)*(n+1)
337
338    class VIndex:
339
340        def __init__(self, n,m):
341            self.n = n
342            self.m = m
343
344        def __call__(self, i,j):
345            return j+i*(self.n+1)
346
347    class EIndex:
348
349        def __init__(self, n,m):
350            self.n = n
351            self.m = m
352
353        def __call__(self, i,j):
354            return 2*(j+i*self.n)
355
356
357    I = VIndex(n,m)
358    E = EIndex(n,m)
359
360    points = zeros( (Np,2), Float)
361
362    for i in range(m+1):
363        for j in range(n+1):
364
365            points[I(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
366
367    #Construct 2 triangles per rectangular element and assign tags to boundary
368    #Calculate number of triangles
369    Nt = 2*m*n
370
371
372    elements = zeros( (Nt,3), Int)
373    boundary = {}
374    ghosts = {}
375    nt = -1
376    for i in range(m):
377        for j in range(n):
378
379            i1 = I(i,j+1)
380            i2 = I(i,j)
381            i3 = I(i+1,j+1)
382            i4 = I(i+1,j)
383
384            #Lower Element
385            nt = E(i,j)
386            if i == m-1:
387                ghosts[nt] = E(1,j)
388            if i == 0:
389                ghosts[nt] = E(m-2,j)
390
391            if j == n-1:
392                ghosts[nt] = E(i,1)
393
394            if j == 0:
395                ghosts[nt] = E(i,n-2)
396
397            if i == m-1:
398                boundary[nt, 2] = 'right'
399            if j == 0:
400                boundary[nt, 1] = 'bottom'
401            elements[nt,:] = [i4,i3,i2]
402
403            #Upper Element
404            nt = E(i,j)+1
405            if i == m-1:
406                ghosts[nt] = E(1,j)+1
407            if i == 0:
408                ghosts[nt] = E(m-2,j)+1
409
410            if j == n-1:
411                ghosts[nt] = E(i,1)+1
412
413            if j == 0:
414                ghosts[nt] = E(i,n-2)+1
415
416            if i == 0:
417                boundary[nt, 2] = 'left'
418            if j == n-1:
419                boundary[nt, 1] = 'top'
420            elements[nt,:] = [i1,i2,i3]
421
422    #bottom left
423    nt = E(0,0)
424    nf = E(m-2,n-2)
425    ghosts[nt]   = nf
426    ghosts[nt+1] = nf+1
427
428    #bottom right
429    nt = E(m-1,0)
430    nf = E(1,n-2)
431    ghosts[nt]   = nf
432    ghosts[nt+1] = nf+1
433
434    #top left
435    nt = E(0,n-1)
436    nf = E(m-2,1)
437    ghosts[nt]   = nf
438    ghosts[nt+1] = nf+1
439
440    #top right
441    nt = E(m-1,n-1)
442    nf = E(1,1)
443    ghosts[nt]   = nf
444    ghosts[nt+1] = nf+1
445
446    return points, elements, boundary, ghosts
447
448def rectangular_periodic_lr(m, n, len1=1.0, len2=1.0, origin = (0.0, 0.0)):
449
450
451    """Setup a rectangular grid of triangles
452    with m+1 by n+1 grid points
453    and side lengths len1, len2. If side lengths are omitted
454    the mesh defaults to the unit square.
455
456    len1: x direction (left to right)
457    len2: y direction (bottom to top)
458
459    Return to lists: points and elements suitable for creating a Mesh or
460    Domain object, e.g. Mesh(points, elements)
461    """
462
463    from config import epsilon
464    from Numeric import zeros, Float, Int
465
466    delta1 = float(len1)/m
467    delta2 = float(len2)/n
468
469    #Calculate number of points
470    Np = (m+1)*(n+1)
471
472    class VIndex:
473
474        def __init__(self, n,m):
475            self.n = n
476            self.m = m
477
478        def __call__(self, i,j):
479            return j+i*(self.n+1)
480
481    class EIndex:
482
483        def __init__(self, n,m):
484            self.n = n
485            self.m = m
486
487        def __call__(self, i,j):
488            return 2*(j+i*self.n)
489
490
491    I = VIndex(n,m)
492    E = EIndex(n,m)
493
494    points = zeros( (Np,2), Float)
495
496    for i in range(m+1):
497        for j in range(n+1):
498
499            points[I(i,j),:] = [i*delta1 + origin[0], j*delta2 + origin[1]]
500
501    #Construct 2 triangles per rectangular element and assign tags to boundary
502    #Calculate number of triangles
503    Nt = 2*m*n
504
505
506    elements = zeros( (Nt,3), Int)
507    boundary = {}
508    ghosts = {}
509    nt = -1
510    for i in range(m):
511        for j in range(n):
512
513            i1 = I(i,j+1)
514            i2 = I(i,j)
515            i3 = I(i+1,j+1)
516            i4 = I(i+1,j)
517
518            #Lower Element
519            nt = E(i,j)
520            if i == m-1:
521                ghosts[nt] = E(1,j)
522            if i == 0:
523                ghosts[nt] = E(m-2,j)
524
525            if i == m-1:
526                boundary[nt, 2] = 'right'
527            if j == 0:
528                boundary[nt, 1] = 'bottom'
529            elements[nt,:] = [i4,i3,i2]
530
531            #Upper Element
532            nt = E(i,j)+1
533            if i == m-1:
534                ghosts[nt] = E(1,j)+1
535            if i == 0:
536                ghosts[nt] = E(m-2,j)+1
537
538            if i == 0:
539                boundary[nt, 2] = 'left'
540            if j == n-1:
541                boundary[nt, 1] = 'top'
542            elements[nt,:] = [i1,i2,i3]
543
544
545    return points, elements, boundary, ghosts
Note: See TracBrowser for help on using the repository browser.