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

Last change on this file since 643 was 271, checked in by ole, 20 years ago

Made evlove specialisation in advection module

File size: 5.7 KB
Line 
1"""Class Domain -
22D triangular domains for finite-volume computations of
3the advection equation.
4
5This module contains a specialisation of class Domain from module domain.py
6consisting of methods specific to the advection equantion
7
8The equation is
9
10  u_t + (v_1 u)_x + (v_2 u)_y = 0
11
12There is only one conserved quantity, the level u
13
14The advection equation is a very simple specialisation of the generic
15domain and may serve as an instructive example or a test of other
16components such as visualisation.
17
18Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
19Geoscience Australia, 2004   
20"""
21
22from domain import *
23Generic_domain = Domain #Rename
24
25class Domain(Generic_domain):
26
27    def __init__(self, coordinates, vertices, boundary = None, velocity = None):
28
29       
30        Generic_domain.__init__(self, coordinates, vertices, boundary,
31                                ['level'])
32
33        if velocity is None:
34            self.velocity = [1,0]
35        else:
36            self.velocity = velocity
37
38        #Only first is implemented for advection   
39        self.default_order = self.order = 1 
40
41        #Realtime visualisation
42        self.visualise = False
43        self.smooth = True
44
45
46    def check_integrity(self):
47        Generic_domain.check_integrity(self)
48
49        msg = 'Conserved quantity must be "level"'
50        assert self.conserved_quantities[0] == 'level', msg
51       
52
53    def flux_function(self, normal, ql, qr, zl=None, zr=None):
54        """Compute outward flux as inner product between velocity
55        vector v=(v_1, v_2) and normal vector n.
56           
57        if <n,v> > 0 flux direction is outward bound and its magnitude is
58        determined by the quantity inside volume: ql.
59        Otherwise it is inbound and magnitude is determined by the
60        quantity outside the volume: qr.
61        """
62   
63        v1 = self.velocity[0]
64        v2 = self.velocity[1]
65
66
67        normal_velocity = v1*normal[0] + v2*normal[1]
68
69        if normal_velocity < 0:
70            flux = qr * normal_velocity
71        else:
72            flux = ql * normal_velocity
73       
74        max_speed = abs(normal_velocity)
75        return flux, max_speed       
76
77       
78    def compute_fluxes(self):
79        """Compute all fluxes and the timestep suitable for all volumes
80        in domain.
81       
82        Compute total flux for each conserved quantity using "flux_function"
83       
84        Fluxes across each edge are scaled by edgelengths and summed up
85        Resulting flux is then scaled by area and stored in
86        domain.explicit_update
87
88        The maximal allowable speed computed by the flux_function
89        for each volume
90        is converted to a timestep that must not be exceeded. The minimum of
91        those is computed as the next overall timestep.
92
93        Post conditions:
94        domain.explicit_update is reset to computed flux values
95        domain.timestep is set to the largest step satisfying all volumes.
96        """
97
98        import sys
99        from Numeric import zeros, Float
100        from config import max_timestep
101
102        N = self.number_of_elements
103   
104        neighbours = self.neighbours
105        neighbour_edges = self.neighbour_edges
106        normals = self.normals
107
108        areas = self.areas
109        radii = self.radii
110        edgelengths = self.edgelengths
111           
112        timestep = max_timestep #FIXME: Get rid of this
113
114        #Shortcuts
115        Level = self.quantities['level']
116
117        #Arrays
118        level = Level.edge_values
119
120        level_bdry = Level.boundary_values
121   
122        flux = zeros(1, Float) #Work array for summing up fluxes
123
124        #Loop
125        for k in range(N):
126            optimal_timestep = float(sys.maxint)
127
128            flux[:] = 0.  #Reset work array
129            for i in range(3):
130                #Quantities inside volume facing neighbour i
131                ql = level[k, i]
132
133                #Quantities at neighbour on nearest face
134                n = neighbours[k,i] 
135                if n < 0:
136                    m = -n-1 #Convert neg flag to index
137                    qr = level_bdry[m]
138                else:   
139                    m = neighbour_edges[k,i]
140                    qr = level[n, m]
141
142                   
143                #Outward pointing normal vector   
144                normal = normals[k, 2*i:2*i+2]
145
146                #Flux computation using provided function
147                edgeflux, max_speed = self.flux_function(normal, ql, qr)
148                flux -= edgeflux * edgelengths[k,i]
149               
150                #Update optimal_timestep
151                try:
152                    optimal_timestep = min(optimal_timestep, radii[k]/max_speed)
153                except ZeroDivisionError:
154                    pass
155
156            #Normalise by area and store for when all conserved
157            #quantities get updated
158            flux /= areas[k]
159            Level.explicit_update[k] = flux[0]
160           
161            timestep = min(timestep, optimal_timestep)
162
163        self.timestep = timestep   
164       
165
166
167    def evolve(self, yieldstep = None, finaltime = None):
168        """Specialisation of basic evolve method from parent class
169        """
170       
171        #Initialise real time viz if requested
172        if self.visualise is True and self.time == 0.0:
173            import realtime_visualisation as visualise
174            visualise.create_surface(self)
175
176        #Call basic machinery from parent class
177        for t in Generic_domain.evolve(self, yieldstep, finaltime):
178            #Real time viz
179            if self.visualise is True:
180                visualise.update(self)
181
182            #Pass control on to outer loop for more specific actions   
183            yield(t)
184       
Note: See TracBrowser for help on using the repository browser.