source: inundation/ga/storm_surge/pyvolution/advection.py @ 1564

Last change on this file since 1564 was 1564, checked in by ole, 19 years ago

Moved visualiser import to initialiser

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