source: inundation/ga/storm_surge/parallel/advection.py @ 1471

Last change on this file since 1471 was 1471, checked in by steve, 19 years ago

Can now change base colour for different quantities, but need a better method!

File size: 10.2 KB
Line 
1import sys
2from os import sep
3sys.path.append('..'+sep+'pyvolution')
4
5"""Class Domain -
62D triangular domains for finite-volume computations of
7the advection equation.
8
9This module contains a specialisation of class Domain from module domain.py
10consisting of methods specific to the advection equantion
11
12The equation is
13
14  u_t + (v_1 u)_x + (v_2 u)_y = 0
15
16There is only one conserved quantity, the stage u
17
18The advection equation is a very simple specialisation of the generic
19domain and may serve as an instructive example or a test of other
20components such as visualisation.
21
22Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
23Geoscience Australia, 2004
24"""
25
26from realtime_visualisation_new import Visualiser
27from domain import *
28Generic_domain = Domain #Rename
29
30class Domain(Generic_domain):
31
32    def __init__(self, coordinates, vertices, boundary = None, velocity = None):
33
34
35        Generic_domain.__init__(self, coordinates, vertices, boundary,['stage'])
36
37        if velocity is None:
38            self.velocity = [1,0]
39        else:
40            self.velocity = velocity
41
42        #Only first is implemented for advection
43        self.default_order = self.order = 1
44
45        #Realtime visualisation
46        self.visualiser = None
47        self.visualise  = False
48        self.visualise_color_stage = False
49        self.visualise_timer = True
50        self.visualise_range_z = None
51
52        self.smooth = True
53
54
55
56    def initialise_visualiser(self,scale_z=1.0):
57        #Realtime visualisation
58        self.visualiser = Visualiser(self,scale_z)
59        self.visualise = True
60
61
62    def check_integrity(self):
63        Generic_domain.check_integrity(self)
64
65        msg = 'Conserved quantity must be "stage"'
66        assert self.conserved_quantities[0] == 'stage', msg
67
68
69    def flux_function(self, normal, ql, qr, zl=None, zr=None):
70        """Compute outward flux as inner product between velocity
71        vector v=(v_1, v_2) and normal vector n.
72
73        if <n,v> > 0 flux direction is outward bound and its magnitude is
74        determined by the quantity inside volume: ql.
75        Otherwise it is inbound and magnitude is determined by the
76        quantity outside the volume: qr.
77        """
78
79        v1 = self.velocity[0]
80        v2 = self.velocity[1]
81
82
83        normal_velocity = v1*normal[0] + v2*normal[1]
84
85        if normal_velocity < 0:
86            flux = qr * normal_velocity
87        else:
88            flux = ql * normal_velocity
89
90        max_speed = abs(normal_velocity)
91        return flux, max_speed
92
93    def compute_fluxes(self):
94
95        self.compute_fluxes_weave()
96
97    def compute_fluxes_python(self):
98        """Compute all fluxes and the timestep suitable for all volumes
99        in domain.
100
101        Compute total flux for each conserved quantity using "flux_function"
102
103        Fluxes across each edge are scaled by edgelengths and summed up
104        Resulting flux is then scaled by area and stored in
105        domain.explicit_update
106
107        The maximal allowable speed computed by the flux_function
108        for each volume
109        is converted to a timestep that must not be exceeded. The minimum of
110        those is computed as the next overall timestep.
111
112        Post conditions:
113        domain.explicit_update is reset to computed flux values
114        domain.timestep is set to the largest step satisfying all volumes.
115        """
116
117        import sys
118        from Numeric import zeros, Float
119        from config import max_timestep
120
121        N = self.number_of_elements
122
123        neighbours = self.neighbours
124        neighbour_edges = self.neighbour_edges
125        normals = self.normals
126
127        areas = self.areas
128        radii = self.radii
129        edgelengths = self.edgelengths
130
131        timestep = max_timestep #FIXME: Get rid of this
132
133        #Shortcuts
134        Stage = self.quantities['stage']
135
136        #Arrays
137        stage = Stage.edge_values
138
139        stage_bdry = Stage.boundary_values
140
141        flux = zeros(1, Float) #Work array for summing up fluxes
142
143        #Loop
144        for k in range(N):
145            optimal_timestep = float(sys.maxint)
146
147            flux[:] = 0.  #Reset work array
148            for i in range(3):
149                #Quantities inside volume facing neighbour i
150                ql = stage[k, i]
151
152                #Quantities at neighbour on nearest face
153                n = neighbours[k,i]
154                if n < 0:
155                    m = -n-1 #Convert neg flag to index
156                    qr = stage_bdry[m]
157                else:
158                    m = neighbour_edges[k,i]
159                    qr = stage[n, m]
160
161
162                #Outward pointing normal vector
163                normal = normals[k, 2*i:2*i+2]
164
165                #Flux computation using provided function
166                edgeflux, max_speed = self.flux_function(normal, ql, qr)
167                flux -= edgeflux * edgelengths[k,i]
168
169                #Update optimal_timestep
170                try:
171                    optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
172                except ZeroDivisionError:
173                    pass
174
175            #Normalise by area and store for when all conserved
176            #quantities get updated
177            flux /= areas[k]
178            Stage.explicit_update[k] = flux[0]
179
180            timestep = min(timestep, optimal_timestep)
181
182        self.timestep = timestep
183
184    def compute_fluxes_weave(self):
185        """Compute all fluxes and the timestep suitable for all volumes
186        in domain.
187
188        Compute total flux for each conserved quantity using "flux_function"
189
190        Fluxes across each edge are scaled by edgelengths and summed up
191        Resulting flux is then scaled by area and stored in
192        domain.explicit_update
193
194        The maximal allowable speed computed by the flux_function
195        for each volume
196        is converted to a timestep that must not be exceeded. The minimum of
197        those is computed as the next overall timestep.
198
199        Post conditions:
200        domain.explicit_update is reset to computed flux values
201        domain.timestep is set to the largest step satisfying all volumes.
202        """
203
204        import sys
205        from Numeric import zeros, Float
206        from config import max_timestep
207
208        import weave
209        from weave import converters
210
211        N = self.number_of_elements
212
213
214        timestep    = zeros( 1, Float);
215        timestep[0] = float(max_timestep) #FIXME: Get rid of this
216
217        #Shortcuts
218        Stage = self.quantities['stage']
219
220        #Arrays
221        neighbours      = self.neighbours
222        neighbour_edges = self.neighbour_edges
223        normals         = self.normals
224        areas           = self.areas
225        radii           = self.radii
226        edgelengths     = self.edgelengths
227
228        stage_edge      = Stage.edge_values
229        stage_bdry      = Stage.boundary_values
230        stage_update    = Stage.explicit_update
231
232        huge_timestep = float(sys.maxint)
233
234        v1 = self.velocity[0]
235        v2 = self.velocity[1]
236
237        code = """
238        //Loop
239
240        double qr,ql;
241        int m,n;
242        double normal[2];
243        double normal_velocity;
244        double flux, edgeflux;
245        double max_speed;
246        double optimal_timestep;
247        for (int k=0; k<N; k++){
248
249            optimal_timestep = huge_timestep;
250            flux = 0.0;  //Reset work array
251            for (int i=0; i<3; i++){
252                //Quantities inside volume facing neighbour i
253                ql = stage_edge(k, i);
254
255                //Quantities at neighbour on nearest face
256                n = neighbours(k,i);
257                if (n < 0) {
258                    m = -n-1; //Convert neg flag to index
259                    qr = stage_bdry(m);
260                } else {
261                    m = neighbour_edges(k,i);
262                    qr = stage_edge(n, m);
263                }
264
265
266                //Outward pointing normal vector
267                for (int j=0; j<2; j++){
268                    normal[j] = normals(k, 2*i+j);
269                }
270
271
272                //Flux computation using provided function
273                normal_velocity = v1*normal[0] + v2*normal[1];
274
275                if (normal_velocity < 0) {
276                    edgeflux = qr * normal_velocity;
277                } else {
278                    edgeflux = ql * normal_velocity;
279                }
280
281                max_speed = fabs(normal_velocity);
282                flux = flux - edgeflux * edgelengths(k,i);
283
284                //Update optimal_timestep
285                if (max_speed != 0.0) {
286                    optimal_timestep = (optimal_timestep>radii(k)/max_speed) ? radii(k)/max_speed : optimal_timestep;
287                }
288
289            }
290
291            //Normalise by area and store for when all conserved
292            //quantities get updated
293            stage_update(k) = flux/areas(k);
294
295            timestep(0) = (timestep(0)>optimal_timestep) ? optimal_timestep : timestep(0);
296
297        }
298        """
299
300        weave.inline(code, ['stage_edge','stage_bdry','stage_update',
301                             'neighbours','neighbour_edges','normals',
302                             'areas','radii','edgelengths','huge_timestep',
303                             'timestep','v1','v2','N'],
304                             type_converters = converters.blitz, compiler='gcc');
305
306        self.timestep = timestep[0]
307
308
309    def evolve(self, yieldstep = None, finaltime = None):
310        """Specialisation of basic evolve method from parent class
311        """
312
313        #Initialise real time viz if requested
314        if self.visualise is True and self.time == 0.0:
315            #import realtime_visualisation_new as visualise
316            self.visualiser.update_quantity('stage')
317            self.visualiser.update_timer()
318
319        #Call basic machinery from parent class
320        for t in Generic_domain.evolve(self, yieldstep, finaltime):
321            #Real time viz
322            if self.visualise is True:
323                self.visualiser.update_quantity('stage')
324                self.visualiser.update_timer()
325
326            #Pass control on to outer loop for more specific actions
327            yield(t)
Note: See TracBrowser for help on using the repository browser.